/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.isis.applib.value; import org.joda.time.DateTime; import org.joda.time.DateTimeFieldType; import org.joda.time.Period; import org.joda.time.format.DateTimeFormat; import org.apache.isis.applib.Defaults; import org.apache.isis.applib.annotation.Value; import org.apache.isis.applib.clock.Clock; /** * Value object representing a date (not time) value. * * <p> * TODO: other methods to implement comparison methods: * <ul> * <li>sameDateAs() day == day & month == month & year == year</li> * <li>withinNextDatePeriod(int days, int months, int years)</li> * <li>withinDatePeriod(int days, int months, int years)</li> * <li>withinPreviousDatePeriod(int days, int months, int years)</li> * </ul> */ @Value(semanticsProviderName = "org.apache.isis.core.metamodel.facets.value.date.DateValueSemanticsProvider") public class Date extends Magnitude<Date> { private static final long serialVersionUID = 1L; private final DateTime date; /** * Create a Date object for today's date. */ public Date() { final DateTime time = Clock.getTimeAsDateTime().withTime(0, 0, 0, 0); date = new DateTime(time, Defaults.getTimeZone()); } /** * Create a Date object set to the specified day, month and year. */ public Date(final int year, final int month, final int day) { checkDate(year, month, day); date = newDateTime(year, month, day); } /** * Create a Date object based on the specified Java date object. The time * portion of the Java date is disposed of. */ public Date(final java.util.Date date) { this.date = new DateTime(date.getTime(), Defaults.getTimeZone()); } public Date(final long millisSinceEpoch) { this.date = new DateTime(millisSinceEpoch); } public Date(final DateTime date) { this.date = new DateTime(date); } private DateTime newDateTime(final int year, final int month, final int day) { return new DateTime(year, month, day, 0, 0, 0, 0, Defaults.getTimeZone()); } protected Date createDate(final DateTime date) { final Date newDate = new Date(date); return newDate; } /** * Add the specified days, years and months to this date value and return a * new date object containing the result. */ public Date add(final int years, final int months, final int days) { final Period add = new Period(years, months, 0, days, 0, 0, 0, 0); final DateTime newDate = date.plus(add); return new Date(newDate); } private void checkDate(final int year, final int month, final int day) { if ((month < 1) || (month > 12)) { throw new IllegalArgumentException("Month must be in the range 1 - 12 inclusive"); } final DateTime newDate = newDateTime(year, month, 1); final int lastDayOfMonth = newDate.dayOfMonth().getMaximumValue(); ; if ((day < 1) || (day > lastDayOfMonth)) { throw new IllegalArgumentException("Day must be in the range 1 - " + lastDayOfMonth + " inclusive: " + day); } } /** * Return this date value as a Java Date object. * * @see java.util.Date */ public java.util.Date dateValue() { final java.util.Date javaDate = date.toDate(); return javaDate; } /** * * @return the milliseconds from 1970-01-01T00:00:00Z */ public long getMillisSinceEpoch() { return date.getMillis(); } /** * Calculates, and returns, a date representing the last day of the month * relative to the current date. * * @author Joshua Cassidy */ public Date endOfMonth() { return new Date(date.dayOfMonth().withMaximumValue()); } @Override public boolean equals(final Object o) { if (this == o) { return true; } if (!(o instanceof Date)) { return false; } final Date date1 = (Date) o; if (!date.equals(date1.date)) { return false; } return true; } @Override public int hashCode() { return date.hashCode(); } /** * Return the day from this date, in the range 1 - 31. */ public int getDay() { return date.getDayOfMonth(); } /** * Calculates, and returns, an int representing the day of the week relative * to the current date. With Mon = 0 through to Sun = 6 * * @author Joshua Cassidy */ public int getDayOfWeek() { return date.getDayOfWeek() - 1; // Mon - Sun == 1 - 7 } /** * Return the month from this date, in the range 1 - 12. */ public int getMonth() { return date.getMonthOfYear(); } /** * Return the year from this date. */ public int getYear() { return date.getYear(); } /** * Returns true if the date of this object has the same value as the * specified date */ @Override public boolean isEqualTo(final Date date) { return this.date.equals((date).date); } /** * Returns true if the time of this object is earlier than the specified * time */ @Override public boolean isLessThan(final Date date) { return this.date.isBefore((date).date); } private boolean sameAs(final Date as, final DateTimeFieldType field) { return date.get(field) == as.date.get(field); } /** * Determines if this date and the specified date represent the same day of * the month, eg both dates are for the 3rd. */ public boolean sameDayOfMonthAs(final Date as) { return sameAs(as, DateTimeFieldType.dayOfMonth()); } /** * Determines if this date and the specified date represent the same day of * the week, eg both dates are on a Tuesday. */ public boolean sameDayOfWeekAs(final Date as) { return sameAs(as, DateTimeFieldType.dayOfWeek()); } /** * Determines if this date and the specified date represent the same day of * the year, eg both dates are for the 108th day of the year. */ public boolean sameDayOfYearAs(final Date as) { return sameAs(as, DateTimeFieldType.dayOfYear()); } /** * Determines if this date and the specified date represent the same month, * eg both dates are for the March. */ public boolean sameMonthAs(final Date as) { return sameAs(as, DateTimeFieldType.monthOfYear()); } /** * Determines if this date and the specified date represent the same week in * the year, eg both dates are the for the 18th week of the year. */ public boolean sameWeekAs(final Date as) { return sameAs(as, DateTimeFieldType.weekOfWeekyear()); } /** * Determines if this date and the specified date represent the same year. */ public boolean sameYearAs(final Date as) { return sameAs(as, DateTimeFieldType.year()); } /** * Calculates, and returns, a date representing the first day of the month * relative to the current date. */ public Date startOfMonth() { return new Date(date.dayOfMonth().withMinimumValue()); } /** * Calculates, and returns, a date representing the first day of the week * relative to the current date. */ public Date startOfWeek() { return new Date(date.dayOfWeek().withMinimumValue()); } /** * Calculates, and returns, a date representing the first day of the year * relative to the current date. */ public Date startOfYear() { return new Date(date.dayOfYear().withMinimumValue()); } public String title() { return DateTimeFormat.mediumDate().print(date); } @Override public String toString() { // return getYear() + "-" + getMonth() + "-" + getDay(); return String.format("%04d-%02d-%02d", getYear(), getMonth(), getDay()); } }