All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jodd.datetime.JDateTime Maven / Gradle / Ivy

There is a newer version: 5.3.0
Show newest version
// Copyright (c) 2003-present, Jodd Team (http://jodd.org)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

package jodd.datetime;

import jodd.datetime.format.JdtFormat;
import jodd.datetime.format.JdtFormatter;
import jodd.util.HashCode;

import java.io.Serializable;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

/**
 * Universal all-in-one date and time class that uses Astronomical Julian
 * Dates for time calculations. Guaranteed precision for all manipulations
 * and calculations is up to 1 ms (0.001 sec).
 *
 * 

* The Julian day or Julian day number (JDN) is the (integer) number of days that * have elapsed since Monday, January 1, 4713 BC in the proleptic Julian calendar 1. * That day is counted as Julian day zero. Thus the multiples of 7 are Mondays. * Negative values can also be used. * *

* The Julian Date (JD) is the number of days (with decimal fraction of the day) that * have elapsed since 12 noon Greenwich Mean Time (UT or TT) of that day. * Rounding to the nearest integer gives the Julian day number. * *

* JDateTime contains date/time information for current day. By * default, behaviour and formats are set to ISO standard, although this may * be changed. * *

* JDateTime can be set in many different ways by using setXxx() * methods or equivalent constructors. Moreover, date time information may be loaded from an instance * of any available java date-time class. This functionality can be easily * enhanced for any custom date/time class. Furthermore, JDateTime * can be converted to any such date/time class. * *

* Rolling dates with JDateTime is easy. For this * JDateTime contains many addXxx() methods. Time can be added * or subtracted with any value or more values at once. All combinations are * valid. Calculations also performs month fixes by default. * *

* JDateTime behaviour is set by several attributes (or * parameters). Each one contains 2 values: one is the default value, used by * all instances of JDateTime and the other one is just for a * specific instance of JDateTime. This means that it is * possible to set behaviour of all instances at once or of one particular * instance. * *

* Bellow is the list of behaviour attributes: * *

    * *
  • monthFix - since months do not have the same number of days, adding * months and years may be calculated in two different ways: with or * without month fix. when month fix is on, JDateTime will * additionally fix all time adding and fix the date. For example, adding * one month to 2003-01-31 will give 2003-02-28 and not 2003-03-03. * By default, monthFix is turned on and set to true. *
  • * *
  • locale - current locale, used for getting names during formatting the * output string. *
  • * *
  • timezone - current timezone
  • * *
  • format - is String that describes how time is converted and parsed to * and from a String. Default format matches ISO standard. An instance of * JdtFormatter parses and uses this template.
  • * *
  • week definition - is used for specifying the definition of the week. * Week is defined with first day of the week and with the must have day. A * must have day is a day that must exist in the 1st week of the year. For * example, default value is Thursday (4) as specified by ISO standard. * Alternatively, instead of must have day, minimal days of week may be used, * since this two numbers are in relation. *
  • * *
* * Optimization: although based on heavy calculations, JDateTime * works significantly faster then java's Calendars. Since * JDateTime doesn't use lazy initialization, setXxx() method is * slower. However, this doesn't have much effect to the global performances: * settings are usually not used without gettings:) As soon as any other method is * used (getXxx() or addXxx()) performances of JDateTime becomes * significantly better. * *

* Year 1582 is (almost:) working: after 1582-10-04 (Thursday) is 1582-10-15 (Friday). * Users must be aware of this when doing time rolling before across this period. * *

* More info: Julian Date on Wikipedia */ public class JDateTime implements Comparable, Cloneable, Serializable { public static final String DEFAULT_FORMAT = "YYYY-MM-DD hh:mm:ss.mss"; // day of week names public static final int MONDAY = 1; public static final int TUESDAY = 2; public static final int WEDNESDAY = 3; public static final int THURSDAY = 4; public static final int FRIDAY = 5; public static final int SATURDAY = 6; public static final int SUNDAY = 7; // month names public static final int JANUARY = 1; public static final int FEBRUARY = 2; public static final int MARCH = 3; public static final int APRIL = 4; public static final int MAY = 5; public static final int JUNE = 6; public static final int JULY = 7; public static final int AUGUST = 8; public static final int SEPTEMBER = 9; public static final int OCTOBER = 10; public static final int NOVEMBER = 11; public static final int DECEMBER = 12; /** * {@link DateTimeStamp} for current date. */ protected DateTimeStamp time = new DateTimeStamp(); /** * Day of week, range: [1-7] == [Monday - Sunday] */ protected int dayofweek; /** * Day of year, range: [1-365] or [1-366] */ protected int dayofyear; /** * Leap year flag. */ protected boolean leap; /** * Week of year, range: [1-52] or [1-53] */ protected int weekofyear; /** * Week of month. */ protected int weekofmonth; /** * Current Julian Date. */ protected JulianDateStamp jdate; // ---------------------------------------------------------------- some precalculated times /** * Julian Date for 1970-01-01T00:00:00 (Thursday). */ public static final JulianDateStamp JD_1970 = new JulianDateStamp(2440587, 0.5); /** * Julian Date for 2001-01-01T00:00:00 (Monday). */ public static final JulianDateStamp JD_2001 = new JulianDateStamp(2451910, 0.5); // ---------------------------------------------------------------- julian date (CORE) /** * Returns current {@link DateTimeStamp}. * Returned instance is still used internally (i.e. it is not cloned before returning). */ public DateTimeStamp getDateTimeStamp() { return time; } /** * Loads current date time information. */ public JDateTime setDateTimeStamp(final DateTimeStamp dts) { return set(dts.year, dts.month, dts.day, dts.hour, dts.minute, dts.second, dts.millisecond); } /** * Sets current Julian Date. This is the core of the JDateTime class and it * is used by all other classes. This method performs all calculations * required for whole class. * * @param jds current julian date */ public JDateTime setJulianDate(final JulianDateStamp jds) { setJdOnly(jds.clone()); calculateAdditionalData(); return this; } /** * Returns {@link JulianDateStamp}. It is the same instance used internally. */ public JulianDateStamp getJulianDate() { return jdate; } /** * Returns JDN. Note that JDN is not equal to integer part of julian date. It is calculated by * rounding to the nearest integer. */ public int getJulianDayNumber() { return jdate.getJulianDayNumber(); } /** * Internal method for calculating various data other then date/time. */ private void calculateAdditionalData() { this.leap = TimeUtil.isLeapYear(time.year); this.dayofweek = calcDayOfWeek(); this.dayofyear = calcDayOfYear(); this.weekofyear = calcWeekOfYear(firstDayOfWeek, mustHaveDayOfFirstWeek); this.weekofmonth = calcWeekNumber(time.day, this.dayofweek); } /** * Internal method that just sets the time stamp and not all other additional * parameters. Used for faster calculations only and only by main core * set/add methods. * * @param jds julian date */ private void setJdOnly(final JulianDateStamp jds) { jdate = jds; time = TimeUtil.fromJulianDate(jds); } /** * Core method that sets date and time. All others set() methods use this * one. Milliseconds are truncated after 3rd digit. * * @param year year to set * @param month month to set * @param day day to set * @param hour hour to set * @param minute minute to set * @param second second to set */ public JDateTime set(final int year, final int month, final int day, final int hour, final int minute, final int second, final int millisecond) { // fix seconds fractions because of float point arithmetic //second = ((int) second) + ((int) ((second - (int)second) * 1000 + 1e-9) / 1000.0); /* double ms = (second - (int)second) * 1000; if (ms > 999) { ms = 999; } else { ms += 1.0e-9; } second = ((int) second) + ((int) ms / 1000.0); */ jdate = TimeUtil.toJulianDate(year, month, day, hour, minute, second, millisecond); // if given time is valid it means that there is no need to calculate it // again from already calculated Julian date. however, it is still // necessary to fix milliseconds to match the value that would be // calculated as setJulianDate() is used. This fix only deals with the // time, not doing the complete and more extensive date calculation. // this means that method works faster when regular date is specified. /* if (TimeUtil.isValidDateTime(year, month, day, hour, minute, second, millisecond)) { int ka = (int)(jdate.fraction + 0.5); double frac = jdate.fraction + 0.5 - ka + 1.0e-10; // hour with minute and second included as fraction double d_hour = frac * 24.0; // minute with second included as a fraction double d_minute = (d_hour - (int)d_hour) * 60.0; second = (d_minute - (int)d_minute) * 60.0; // fix calculation errors second = ((int) (second * 10000) + 0.5) / 10000.0; time.year = year; time.month = month; time.day = day; time.hour = hour; time.minute = minute; time.second = second; setParams(); } else { setJulianDate(jdate); } */ if (TimeUtil.isValidDateTime(year, month, day, hour, minute, second, millisecond)) { time.year = year; time.month = month; time.day = day; time.hour = hour; time.minute = minute; time.second = second; time.millisecond = millisecond; calculateAdditionalData(); } else { setJulianDate(jdate); } return this; } /** * Sets just Julian Date and no other parameter such as day of week etc. * Used internally for speed. * * @param year year to set * @param month month to set * @param day day to set * @param hour hour to set * @param minute minute to set * @param second second to set */ private void setJdOnly(final int year, final int month, final int day, final int hour, final int minute, final int second, final int millisecond) { setJdOnly(TimeUtil.toJulianDate(year, month, day, hour, minute, second, millisecond)); } // ---------------------------------------------------------------- core calculations /** * Calculates day of week. */ private int calcDayOfWeek() { int jd = (int)(jdate.doubleValue() + 0.5); return (jd % 7) + 1; //return (jd + 1) % 7; // return 0 (Sunday), 1 (Monday),... } private static final int[] NUM_DAYS = {-1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; // 1-based private static final int[] LEAP_NUM_DAYS = {-1, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}; // 1-based /** * Calculates day of year. */ private int calcDayOfYear() { if (leap) { return LEAP_NUM_DAYS[time.month] + time.day; } return NUM_DAYS[time.month] + time.day; } /** * Calculates week of year. Based on: * "Algorithm for Converting Gregorian Dates to ISO 8601 Week Date" * by Rick McCarty, 1999 * * @param start first day of week * @param must must have day of week * * @return week of year number */ private int calcWeekOfYear(final int start, final int must) { // is modification required? // modification is a fix for the days of year because of the different // starting day of week. when modification is required, one week is added // or subtracted to the current day, so calculation of the week of year // would be correct. int delta = 0; if (start <= this.dayofweek) { if (must < start) { delta = 7; } } else { if (must >= start) { delta = -7; } } int jd = (int)(jdate.doubleValue() + 0.5) + delta; int WeekDay = (jd % 7) + 1; int time_year = time.year; int DayOfYearNumber = this.dayofyear + delta; if (DayOfYearNumber < 1) { time_year--; DayOfYearNumber = TimeUtil.isLeapYear(time_year) ? 366 + DayOfYearNumber: 365 + DayOfYearNumber; } else if (DayOfYearNumber > (this.leap ? 366 : 365)) { DayOfYearNumber = this.leap ? DayOfYearNumber - 366: DayOfYearNumber - 365; time_year++; } // modification, if required, is finished. proceed to the calculation. int firstDay = jd - DayOfYearNumber + 1; int Jan1WeekDay = (firstDay % 7) + 1; // find if the date falls in YearNumber Y - 1 set WeekNumber to 52 or 53 int YearNumber = time_year; int WeekNumber = 52; if ((DayOfYearNumber <= (8 - Jan1WeekDay)) && (Jan1WeekDay > must)) { YearNumber--; if ((Jan1WeekDay == must + 1) || ( (Jan1WeekDay == must + 2) && (TimeUtil.isLeapYear(YearNumber)) ) ) { WeekNumber = 53; } } // set WeekNumber to 1 to 53 if date falls in YearNumber int m = 365; if (YearNumber == time_year) { if (TimeUtil.isLeapYear(time_year)) { m = 366; } if ((m - DayOfYearNumber) < (must - WeekDay)) { YearNumber = time_year + 1; WeekNumber = 1; } } if (YearNumber == time_year) { int n = DayOfYearNumber + (7 - WeekDay) + (Jan1WeekDay - 1); WeekNumber = n / 7; if (Jan1WeekDay > must) { WeekNumber -= 1; } } return WeekNumber; } /** * Return the week number of a day, within a period. This may be the week number in * a year, or the week number in a month. Usually this will be a value >= 1, but if * some initial days of the period are excluded from week 1, because * minimalDaysInFirstWeek is > 1, then the week number will be zero for those * initial days. Requires the day of week for the given date in order to determine * the day of week of the first day of the period. * * @param dayOfPeriod * Day-of-year or day-of-month. Should be 1 for first day of period. * @param dayOfWeek day of week * * @return Week number, one-based, or zero if the day falls in part of the * month before the first week, when there are days before the first * week because the minimum days in the first week is more than one. */ private int calcWeekNumber(final int dayOfPeriod, final int dayOfWeek) { // Determine the day of the week of the first day of the period // in question (either a year or a month). Zero represents the // first day of the week on this calendar. int periodStartDayOfWeek = (dayOfWeek - firstDayOfWeek - dayOfPeriod + 1) % 7; if (periodStartDayOfWeek < 0) { periodStartDayOfWeek += 7; } // Compute the week number. Initially, ignore the first week, which // may be fractional (or may not be). We add periodStartDayOfWeek in // order to fill out the first week, if it is fractional. int weekNo = (dayOfPeriod + periodStartDayOfWeek - 1) / 7; // If the first week is long enough, then count it. If // the minimal days in the first week is one, or if the period start // is zero, we always increment weekNo. if ((7 - periodStartDayOfWeek) >= minDaysInFirstWeek) { ++weekNo; } return weekNo; } // ---------------------------------------------------------------- add/sub time /** * Adds time to current time. The main add method - all other add() methods * must use this one. *

* There are 2 different kinds of addings, when months are added: *

    *
  • when months are not specially concern. All remaining days will be * added to the next month. Example: 2003-01-31 + 0-01-0 = 2003-03-03
  • *
  • when months addition is fixed, and month is not approximated. * example: 2003-01-31 + 0-01-0 = 2003-02-28
  • *
* * @param year delta year * @param month delta month * @param day delta days * @param hour delta hours * @param minute delta minutes * @param second delta seconds * @param monthFix true for month fixing, false otherwise */ public JDateTime add(final int year, final int month, final int day, final int hour, final int minute, final int second, final int millisecond, final boolean monthFix) { int difference = 0; if (trackDST) { difference = TimeZoneUtil.getOffset(this, timezone); } addNoDST(year, month, day, hour, minute, second, millisecond, monthFix); if (trackDST) { difference = TimeZoneUtil.getOffset(this, timezone) - difference; if (difference != 0) { addNoDST(0, 0, 0, 0, 0, 0, difference, false); } } return this; } protected void addNoDST(int year, int month, int day, int hour, int minute, int second, int millisecond, final boolean monthFix) { millisecond += time.millisecond; second += time.second; minute += time.minute; hour += time.hour; day += time.day; if (!monthFix) { month += time.month; year += time.year; set(year, month, day, hour, minute, second, millisecond); } else { // month fix: // 1. add all except month and year // 2. store day value // 3. add just months // 4. if new date is not equal to stored, return to last day of previous month setJdOnly(time.year, time.month, day, hour, minute, second, millisecond); int from = time.day; month += time.month + (year * 12); // delta years to add are converted to delta months setJdOnly(time.year, month, time.day, time.hour, time.minute, time.second, time.millisecond); if (time.day < from) { set(time.year, time.month, 0, time.hour, time.minute, time.second, time.millisecond); } else { calculateAdditionalData(); } /* // 5. store month value // 6. add just year // 7. if new month is not equal to stored, return to last day of previous month from = time.month; year += time.year; setJdOnly(year, time.month, time.day, time.hour, time.minute, time.second); if (time.month > from) { set(time.year, time.month, 0, time.hour, time.minute, time.second); }*/ } } public JDateTime sub(final int year, final int month, final int day, final int hour, final int minute, final int second, final int millisecond, final boolean monthFix) { return add(-year, -month, -day, -hour, -minute, -second, -millisecond, monthFix); } /** * Performs time adding with preset value of monthFix attribute. * * @param year delta year * @param month delta month * @param day delta days * @param hour delta hours * @param minute delta minutes * @param second delta seconds * * @see #add(int, int, int, int, int, int, int, boolean) */ public JDateTime add(final int year, final int month, final int day, final int hour, final int minute, final int second, final int millisecond) { return add(year, month, day, hour, minute, second, millisecond, monthFix); } public JDateTime sub(final int year, final int month, final int day, final int hour, final int minute, final int second, final int millisecond) { return add(-year, -month, -day, -hour, -minute, -second, millisecond, monthFix); } /** * Adds date, leaving time unchanged. * * @param year years to add * @param month months to add * @param day days to add * @param monthFix true for month fixing, false otherwise * * @see #add(int, int, int, int, int, int, int, boolean) */ public JDateTime add(final int year, final int month, final int day, final boolean monthFix) { return add(year, month, day, 0, 0, 0, 0, monthFix); } public JDateTime sub(final int year, final int month, final int day, final boolean monthFix) { return add(-year, -month, -day, 0, 0, 0, 0, monthFix); } /** * Adds date, leaving time unchanged, with preset value of monthFix. * attribute. * * @param year years to add * @param month months to add * @param day days to add * * @see #add(int, int, int, boolean) */ public JDateTime add(final int year, final int month, final int day) { return add(year, month, day, monthFix); } public JDateTime sub(final int year, final int month, final int day) { return add(-year, -month, -day, monthFix); } /** * Adds time. * * @param hour hours to add * @param minute minutes to add * @param second seconds to add * @param monthFix true for month fixing, false otherwise * * @see #add(int, int, int, int, int, int, int) */ public JDateTime addTime(final int hour, final int minute, final int second, final int millisecond, final boolean monthFix) { return add(0, 0, 0, hour, minute, second, millisecond, monthFix); } public JDateTime subTime(final int hour, final int minute, final int second, final int millisecond, final boolean monthFix) { return add(0, 0, 0, -hour, -minute, -second, -millisecond, monthFix); } public JDateTime addTime(final int hour, final int minute, final int second, final boolean monthFix) { return add(0, 0, 0, hour, minute, second, 0, monthFix); } public JDateTime subTime(final int hour, final int minute, final int second, final boolean monthFix) { return add(0, 0, 0, -hour, -minute, -second, 0, monthFix); } /** * Adds time, with preset value of monthFix. * * @param hour hours to add * @param minute minutes to add * @param second seconds to add * * @see #addTime(int, int, int, int, boolean) */ public JDateTime addTime(final int hour, final int minute, final int second, final int millisecond) { return addTime(hour, minute, second, millisecond, monthFix); } public JDateTime subTime(final int hour, final int minute, final int second, final int millisecond) { return addTime(-hour, -minute, -second, -millisecond, monthFix); } public JDateTime addTime(final int hour, final int minute, final int second) { return addTime(hour, minute, second, 0, monthFix); } public JDateTime subTime(final int hour, final int minute, final int second) { return addTime(-hour, -minute, -second, 0, monthFix); } /** * Adds year. * * @param y year to add * @param monthFix true for month fixing, false otherwise */ public JDateTime addYear(final int y, final boolean monthFix) { return add(y, 0, 0, monthFix); } public JDateTime subYear(final int y, final boolean monthFix) { return add(-y, 0, 0, monthFix); } /** * Adds year, with preset value of monthFix. * * @param y year to add */ public JDateTime addYear(final int y) { return addYear(y, monthFix); } public JDateTime subYear(final int y) { return addYear(-y, monthFix); } /** * Adds month. * * @param m month to add * @param monthFix true for month fixing, false otherwise */ public JDateTime addMonth(final int m, final boolean monthFix) { return add(0, m, 0, monthFix); } public JDateTime subMonth(final int m, final boolean monthFix) { return add(0, -m, 0, monthFix); } /** * Adds month, with preset value of monthFix. * * @param m month to add */ public JDateTime addMonth(final int m) { return addMonth(m, monthFix); } public JDateTime subMonth(final int m) { return addMonth(-m, monthFix); } /** * Adds days. * * @param d days to add * @param monthFix true for month fixing, false otherwise */ public JDateTime addDay(final int d, final boolean monthFix) { return add(0, 0, d, monthFix); } public JDateTime subDay(final int d, final boolean monthFix) { return add(0, 0, -d, monthFix); } /** * Adds days, with preset value of monthFix. * * @param d days to add */ public JDateTime addDay(final int d) { return addDay(d, monthFix); } public JDateTime subDay(final int d) { return addDay(-d, monthFix); } /** * Adds hours. * * @param h hours to add * @param monthFix true for month fixing, false otherwise */ public JDateTime addHour(final int h, final boolean monthFix) { return addTime(h, 0, 0, 0, monthFix); } public JDateTime subHour(final int h, final boolean monthFix) { return addTime(-h, 0, 0, 0, monthFix); } /** * Adds hours, with preset value of monthFix. * * @param h hours to add */ public JDateTime addHour(final int h) { return addHour(h, monthFix); } public JDateTime subHour(final int h) { return addHour(-h, monthFix); } /** * Adds minutes. * * @param m minutes to add. * @param monthFix true for month fixing, false otherwise */ public JDateTime addMinute(final int m, final boolean monthFix) { return addTime(0, m, 0, 0, monthFix); } public JDateTime subMinute(final int m, final boolean monthFix) { return addTime(0, -m, 0, 0, monthFix); } /** * Adds minutes, with preset value of monthFix. * * @param m minutes to add. */ public JDateTime addMinute(final int m) { return addMinute(m, monthFix); } public JDateTime subMinute(final int m) { return addMinute(-m, monthFix); } /** * Adds seconds. * * @param s seconds to add * @param monthFix true for month fixing, false otherwise */ public JDateTime addSecond(final int s, final boolean monthFix) { return addTime(0, 0, s, 0, monthFix); } public JDateTime subSecond(final int s, final boolean monthFix) { return addTime(0, 0, -s, 0, monthFix); } /** * Adds seconds, with preset value of monthFix. * * @param s seconds to add */ public JDateTime addSecond(final int s) { return addSecond(s, monthFix); } public JDateTime subSecond(final int s) { return addSecond(-s, monthFix); } /** * Adds milliseconds. * * @param ms milliseconds to add * @param monthFix true for month fixing, false otherwise */ public JDateTime addMillisecond(final int ms, final boolean monthFix) { return addTime(0, 0, 0, ms, monthFix); } public JDateTime subMillisecond(final int ms, final boolean monthFix) { return addTime(0, 0, 0, -ms, monthFix); } /** * Adds milliseconds, with preset value of monthFix. * * @param ms milliseconds to add */ public JDateTime addMillisecond(final int ms) { return addMillisecond(ms, monthFix); } public JDateTime subMillisecond(final int ms) { return addMillisecond(-ms, monthFix); } // ---------------------------------------------------------------- ctors & sets /** * Constructor that set date and time. * * @param year year to set * @param month month to set * @param day day to set * @param hour hours to set * @param minute minutes to set * @param second seconds to set * @param millisecond milliseconds to set * * @see #set(int, int, int, int, int, int, int) */ public JDateTime(final int year, final int month, final int day, final int hour, final int minute, final int second, final int millisecond) { this.set(year, month, day, hour, minute, second, millisecond); } /** * Sets date, time is set to midnight (00:00:00.000). * * @param year year to set * @param month month to set * @param day day to set */ public JDateTime set(final int year, final int month, final int day) { return set(year, month, day, 0, 0, 0, 0); } /** * Constructor that sets just date. Time is set to 00:00:00. * * @param year year to set * @param month month to set * @param day day to set * * @see #set(int, int, int) */ public JDateTime(final int year, final int month, final int day) { this.set(year, month, day); } /** * Sets time, date is unchanged. * * @param hour hours to set * @param minute minutes to set * @param second seconds to set */ public JDateTime setTime(final int hour, final int minute, final int second, final int millisecond) { return set(time.year, time.month, time.day, hour, minute, second, millisecond); } /** * Sets date, time remains unchanged. * * @param year year * @param month month * @param day day */ public JDateTime setDate(final int year, final int month, final int day) { return set(year, month, day, time.hour, time.minute, time.second, time.millisecond); } // ---------------------------------------------------------------- milliseconds /** * Constructor that sets current time specified as time in milliseconds, from * the midnight, January 1, 1970 UTC. * * @param millis time in milliseconds, from the midnight, January 1, 1970 UTC * * @see #setTimeInMillis(long ) */ public JDateTime(final long millis) { setTimeInMillis(millis); } /** * Sets the time based on current time in milliseconds. Current time is * calculated from the midnight, January 1, 1970 UTC. *

* Calculation is divided in two steps, due to precision issues. * * @param millis time in milliseconds, from the midnight, January 1, 1970 UTC */ public JDateTime setTimeInMillis(long millis) { millis += timezone.getOffset(millis); int integer = (int) (millis / TimeUtil.MILLIS_IN_DAY); double fraction = (double)(millis % TimeUtil.MILLIS_IN_DAY) / TimeUtil.MILLIS_IN_DAY; integer += JD_1970.integer; fraction += JD_1970.fraction; return setJulianDate(new JulianDateStamp(integer, fraction)); } /** * Returns time based on current time in milliseconds. Current time is * calculated from the midnight, January 1, 1970 UTC. *

* Due to possible huge values calculation is divided in two steps: * first for fractional difference, and then for integer parts. * * @return time in milliseconds, from the midnight, January 1, 1970 UTC */ public long getTimeInMillis() { double then = (jdate.fraction - JD_1970.fraction) * TimeUtil.MILLIS_IN_DAY; then += (jdate.integer - JD_1970.integer) * TimeUtil.MILLIS_IN_DAY; then -= timezone.getOffset((long) then); then += then > 0 ? 1.0e-6 : -1.0e-6; return (long) then; } // ---------------------------------------------------------------- date/time sets /** * Sets current year. * * @param y year to set */ public JDateTime setYear(final int y) { return setDate(y, time.month, time.day); } /** * Sets current month. * * @param m month to set */ public JDateTime setMonth(final int m) { return setDate(time.year, m, time.day); } /** * Sets current day of month. * * @param d day to set */ public JDateTime setDay(final int d) { return setDate(time.year, time.month, d); } /** * Set current hour. * * @param h hour to set */ public JDateTime setHour(final int h) { return setTime(h, time.minute, time.second, time.millisecond); } /** * Set current minute. * * @param m minutes to set */ public JDateTime setMinute(final int m) { return setTime(time.hour, m, time.second, time.millisecond); } /** * Sets current second. * * @param s seconds and milliseconds to set */ public JDateTime setSecond(final int s) { return setTime(time.hour, time.minute, s, time.millisecond); } public JDateTime setSecond(final int s, final int m) { return setTime(time.hour, time.minute, s, m); } /** * Sets current millisecond. * * @param m milliseconds to set */ public JDateTime setMillisecond(final int m) { return setTime(time.hour, time.minute, time.second, m); } // ---------------------------------------------------------------- date/time gets /** * Returns current year. */ public int getYear() { return time.year; } /** * Returns current month. */ public int getMonth() { return time.month; } /** * Returns current day of month. * @see #getDayOfMonth */ public int getDay() { return time.day; } /** * Returns current day of month. * @see #getDay */ public int getDayOfMonth() { return time.day; } /** * Returns current hour. */ public int getHour() { return time.hour; } /** * Returns current minutes. */ public int getMinute() { return time.minute; } /** * Return current seconds. For an integer value, just cast the returned * value. */ public int getSecond() { return time.second; } /** * Returns current milliseconds. */ public int getMillisecond() { return time.millisecond; } // ---------------------------------------------------------------- other gets /** * Returns current day of week. */ public int getDayOfWeek() { return dayofweek; } /** * Returns current day of year. */ public int getDayOfYear() { return dayofyear; } /** * Returns true if current year is leap year. */ public boolean isLeapYear() { return leap; } /** * Returns current week of year. */ public int getWeekOfYear() { return weekofyear; } /** * Returns current week of month. */ public int getWeekOfMonth() { return weekofmonth; } /** * Returns the length of the specified month in days. */ public int getMonthLength(final int month) { return TimeUtil.getMonthLength(time.year, month, this.leap); } /** * Returns the length of the current month in days. */ public int getMonthLength() { return getMonthLength(time.month); } /** * Returns era: AD(1) or BC(0). */ public int getEra() { return time.year > 0 ? 1 : 0; } /** * Calculates the number of milliseconds of a day. */ public int getMillisOfDay() { return ((((time.hour * 60) + time.minute) * 60) + time.second) * 1000 + time.millisecond; } // ---------------------------------------------------------------- current date time /** * Sets current local date and time. */ public JDateTime setCurrentTime() { return setTimeInMillis(System.currentTimeMillis()); } /** * Constructor that sets current local date and time. */ public JDateTime() { this.setCurrentTime(); } // ---------------------------------------------------------------- conversion /** * Creates JDateTime from Calendar. */ public JDateTime(final Calendar calendar) { setDateTime(calendar); } /** * Sets current date and time from Calendar. */ public JDateTime setDateTime(final Calendar calendar) { setTimeInMillis(calendar.getTimeInMillis()); changeTimeZone(calendar.getTimeZone()); return this; } /** * Creates JDateTime from Date. */ public JDateTime(final Date date) { setDateTime(date); } /** * Sets current date and time from Date. */ public JDateTime setDateTime(final Date date) { return setTimeInMillis(date.getTime()); } /** * Converts to Date instance. */ public Date convertToDate() { return new Date(getTimeInMillis()); } /** * Converts to Calendar instance. */ public Calendar convertToCalendar() { Calendar calendar = Calendar.getInstance(getTimeZone()); calendar.setTimeInMillis(getTimeInMillis()); return calendar; } /** * Converts to java.sql.Date instance. */ public java.sql.Date convertToSqlDate() { return new java.sql.Date(getTimeInMillis()); } /** * Converts to Time instance. */ public Time convertToSqlTime() { return new Time(getTimeInMillis()); } /** * Converts to Timestamp instance. */ public Timestamp convertToSqlTimestamp() { return new Timestamp(getTimeInMillis()); } // ---------------------------------------------------------------- ctors from conversions /** * Creates JDateTime from DateTimeStamp. */ public JDateTime(final DateTimeStamp dts) { setDateTimeStamp(dts); } /** * Creates JDateTime from JulianDateStamp. */ public JDateTime(final JulianDateStamp jds) { setJulianDate(jds); } /** * Creates JDateTime from double that represents JD. */ public JDateTime(final double jd) { setJulianDate(new JulianDateStamp(jd)); } /** * Creates JDateTime from a string. */ public JDateTime(final String src) { parse(src); } /** * Creates JDateTime from a string, using specified template. */ public JDateTime(final String src, final String template) { parse(src, template); } public JDateTime(final String src, final JdtFormat jdtFormat) { parse(src, jdtFormat); } // ---------------------------------------------------------------- dst protected boolean trackDST = JDateTimeDefault.trackDST; public boolean isTrackDST() { return trackDST; } public JDateTime setTrackDST(final boolean trackDST) { this.trackDST = trackDST; return this; } // ---------------------------------------------------------------- monthFix protected boolean monthFix = JDateTimeDefault.monthFix; /** * Returns true if month fix is active. */ public boolean isMonthFix() { return monthFix; } /** * Sets custom month fix value. */ public JDateTime setMonthFix(final boolean monthFix) { this.monthFix = monthFix; return this; } // ---------------------------------------------------------------- timezone protected TimeZone timezone = JDateTimeDefault.timeZone == null ? TimeZone.getDefault() : JDateTimeDefault.timeZone; /** * Changes current timezone. Current time is changed if time zone has been changed. */ public JDateTime changeTimeZone(final TimeZone timezone) { long now = getTimeInMillis(); int difference = TimeZoneUtil.getOffsetDifference(now, this.timezone, timezone); this.timezone = timezone; if (difference != 0) { addMillisecond(difference); } return this; } /** * Changes time zone. Equivalent to: * setTimeZone(from); changeTimeZone(to); */ public JDateTime changeTimeZone(final TimeZone from, final TimeZone to) { this.timezone = from; changeTimeZone(to); return this; } /** * Sets time zone without changing the time. */ public JDateTime setTimeZone(final TimeZone timezone) { this.timezone = timezone; return this; } /** * Return currently active time zone. */ public TimeZone getTimeZone() { return timezone; } /** * Returns true if current date is in * daylight savings time in the time zone. */ public boolean isInDaylightTime() { long now = getTimeInMillis(); int offset = timezone.getOffset(now); int rawOffset = timezone.getRawOffset(); return (offset != rawOffset); } // ---------------------------------------------------------------- locale protected Locale locale = JDateTimeDefault.locale == null ? Locale.getDefault() : JDateTimeDefault.locale; /** * Sets custom locale. */ public JDateTime setLocale(final Locale locale) { this.locale = locale; return this; } /** * Return currently active locale. */ public Locale getLocale() { return locale; } // ---------------------------------------------------------------- format protected String format = JDateTimeDefault.format; /** * Defines default format. */ public JDateTime setFormat(final String format) { this.format = format; return this; } /** * Returns format. */ public String getFormat() { return format; } protected JdtFormatter jdtFormatter = JDateTimeDefault.formatter; /** * Defines custom formatter. */ public JDateTime setJdtFormatter(final JdtFormatter jdtFormatter) { this.jdtFormatter = jdtFormatter; return this; } /** * Returns actual {@link JdtFormatter}. */ public JdtFormatter getJdtFormatter() { return jdtFormatter; } /** * Sets both format and formatter from provided {@link JdtFormat}. */ public JDateTime setJdtFormat(final JdtFormat jdtFormat) { this.format = jdtFormat.getFormat(); this.jdtFormatter = jdtFormat.getFormatter(); return this; } // ---------------------------------------------------------------- toString and parse /** * Returns string representation of date/time in specified format. */ public String toString(final String format) { return jdtFormatter.convert(this, format); } /** * Returns spring representation of current date/time in currently active format. * @see #getFormat() */ @Override public String toString() { return jdtFormatter.convert(this, format); } public String toString(final JdtFormat jdtFormat) { return jdtFormat.convert(this); } /** * Sets date/time from a string given in provided template. * @param src string containing date time information * @param format format template */ public JDateTime parse(final String src, final String format) { setDateTimeStamp(jdtFormatter.parse(src, format)); return this; } /** * Sets date/time from a string and currently active template. * @param src string containing date time information * @see #getFormat() */ public JDateTime parse(final String src) { setDateTimeStamp(jdtFormatter.parse(src, format)); return this; } public JDateTime parse(final String src, final JdtFormat jdtFormat) { setDateTimeStamp(jdtFormat.parse(src)); return this; } /** * Checks if some string represents a valid date using actual template. * * @return true if date is valid, otherwise false */ public boolean isValid(final String s) { return isValid(s, format); } /** * Checks if some string represents a valid date using provided template. * * @return true if date is valid, otherwise false */ public boolean isValid(final String s, final String template) { DateTimeStamp dtsOriginal; try { dtsOriginal = jdtFormatter.parse(s, template); } catch (Exception ignore) { return false; } if (dtsOriginal == null) { return false; } return TimeUtil.isValidDateTime(dtsOriginal); } // ---------------------------------------------------------------- week definitions protected int firstDayOfWeek = JDateTimeDefault.firstDayOfWeek; protected int mustHaveDayOfFirstWeek = JDateTimeDefault.mustHaveDayOfFirstWeek; /** * Defines week definitions. * * @param start first day in week, [1-7], * @param must must have day of the 1st week, [1-7] */ public JDateTime setWeekDefinition(final int start, final int must) { if ((start >= 1) && (start <= 7)) { firstDayOfWeek = start; } if ((must >= 1) && (must <= 7)) { mustHaveDayOfFirstWeek = must; minDaysInFirstWeek = convertMin2Must(firstDayOfWeek, must); } return this; } /** * Returns actual the first day of the week. */ public int getFirstDayOfWeek() { return firstDayOfWeek; } /** * Returns actual must have day of the 1st week. */ public int getMustHaveDayOfFirstWeek() { return mustHaveDayOfFirstWeek; } // ---------------------------------------------------------------- week definitions (alt) protected int minDaysInFirstWeek = JDateTimeDefault.minDaysInFirstWeek; /** * Returns actual minimal number of days of the first week. It is * calculated from must have day of the first week. * * @return minimal number of days of the first week */ public int getMinDaysInFirstWeek() { return minDaysInFirstWeek; } /** * Defines week alternatively. * * @param start first day in week * @param min minimal days of week */ public JDateTime setWeekDefinitionAlt(final int start, final int min) { if ((start >= 1) && (start <= 7)) { firstDayOfWeek = start; } if ((min >= 1) && (min <= 7)) { mustHaveDayOfFirstWeek = convertMin2Must(firstDayOfWeek, min); minDaysInFirstWeek = min; } return this; } /** * Converts minimal day of week to must have day of week. * Method is symmetrical. * * @param start first day of week * @param min minimal day of week * * @return must have day of week */ private static int convertMin2Must(final int start, final int min) { int must = 8 - min + (start - 1); if (must > 7) { must -= 7; } return must; } // ---------------------------------------------------------------- equals & hashCode /** * Compares if two JDateTime instances are equal. * Comparison precision is 1e-3 seconds. */ @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (this.getClass() != obj.getClass()) { return false; } JDateTime jdt = (JDateTime) obj; return (this.monthFix == jdt.monthFix) && (this.firstDayOfWeek == jdt.firstDayOfWeek) && (this.mustHaveDayOfFirstWeek == jdt.mustHaveDayOfFirstWeek) && (this.time.equals(jdt.time)) && (this.timezone.equals(jdt.timezone)); } @Override public int hashCode() { return HashCode.create() .hash(time) .hash(timezone) .hash(monthFix) .hash(firstDayOfWeek) .hash(mustHaveDayOfFirstWeek) .get(); } // ---------------------------------------------------------------- clone @Override public JDateTime clone() { JDateTime jdt = new JDateTime(this.jdate); jdt.monthFix = this.monthFix; jdt.timezone = this.timezone; jdt.locale = this.locale; jdt.format = this.format; jdt.jdtFormatter = this.jdtFormatter; jdt.firstDayOfWeek = this.firstDayOfWeek; jdt.mustHaveDayOfFirstWeek = this.mustHaveDayOfFirstWeek; jdt.trackDST = this.trackDST; return jdt; } // ---------------------------------------------------------------- compare /** * Compares current JDateTime object with another one, up to 1 millisecond. * * @param o JDateTime to compare * * @return -1 if the current object is less than the argument, 0 if the argument is * equal, and 1 if the current object is greater than the argument */ @Override public int compareTo(final Object o) { return time.compareTo(((JDateTime) o).getDateTimeStamp()); } public int compareTo(final JDateTime jd) { return time.compareTo(jd.getDateTimeStamp()); } /** * Compares current JDateTime date with another date. Time component is ignored. */ public int compareDateTo(final JDateTime jd) { return time.compareDateTo(jd.getDateTimeStamp()); } /** * Returns true if current time is after then provided time. */ public boolean isAfter(final JDateTime then) { return time.compareTo((then).getDateTimeStamp()) > 0; } /** * Returns true if current time is before then provided time. */ public boolean isBefore(final JDateTime then) { return time.compareTo((then).getDateTimeStamp()) < 0; } /** * Returns true if current date is after then provided date. * Time component is ignored. */ public boolean isAfterDate(final JDateTime then) { return time.compareDateTo((then).getDateTimeStamp()) > 0; } /** * Returns true if current date is before then provided date. * Time component is ignored. */ public boolean isBeforeDate(final JDateTime then) { return time.compareDateTo((then).getDateTimeStamp()) < 0; } // ---------------------------------------------------------------- difference /** * Returns number of full days between two dates. */ public int daysBetween(final JDateTime then) { return this.jdate.daysBetween(then.jdate); } /** * Returns number of full days between two dates. */ public int daysBetween(final JulianDateStamp then) { return this.jdate.daysBetween(then); } // ---------------------------------------------------------------- alternative representation /** * Returns JD as double value. */ public double getJulianDateDouble() { return jdate.doubleValue(); } /** * Sets JD. */ public JDateTime setJulianDate(final double jd) { return setJulianDate(new JulianDateStamp(jd)); } // ---------------------------------------------------------------- custom equals /** * Returns true if provided date is equal to current one. * May be used for date validation test. */ public boolean equalsDate(final int year, final int month, final int day) { return (time.year == year) && (time.month == month) && (time.day == day); } /** * Returns true if two dates are equal. * Time component is ignored. */ public boolean equalsDate(final JDateTime date) { return time.isEqualDate(date.time); } /** * Returns true if two times are equal. * Date component is ignored. */ public boolean equalsTime(final JDateTime date) { return time.isEqualTime(date.time); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy