//
// Copyright (c) 2006, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
// 3 Jul 06 Brian Frank Creation
//
**
** DateTime represents an absolute instance in time. Fantom time is
** normalized as nanosecond ticks since 1 Jan 2000 UTC with a
** supported range of 1901 to 2099. Fantom time does not support
** leap seconds (same as Java and UNIX). An instance of DateTime
** also models the date and time of an absolute instance against
** a specific `TimeZone`.
**
** Also see [docLang]`docLang::DateTime`.
**
@Serializable { simple = true }
const final class DateTime
{
//////////////////////////////////////////////////////////////////////////
// Constructor
//////////////////////////////////////////////////////////////////////////
**
** Return the current time using `TimeZone.cur`. The tolerance
** parameter specifies that you are willing to use a cached DateTime
** instance as long as (now - cached <= tolerance). If tolerance is null,
** then this method always creates a new DateTime instance. Using
** tolerance can increase performance and save memory. The
** tolerance default is 250ms.
**
** If you are using time to calculate relative time periods,
** then use `Duration.now` instead. Duration is more efficient
** and won't cause you grief when the system clock is modified.
**
static DateTime now(Duration? tolerance := 250ms)
**
** Return the current time using `TimeZone.utc`.
** See `now` for a description of the tolerance parameter.
**
static DateTime nowUtc(Duration? tolerance := 250ms)
**
** Return the current time as nanosecond ticks since 1 Jan 2000 UTC.
**
static Int nowTicks()
**
** Return the current time as nanosecond ticks since 1 Jan 2000 UTC,
** but with the guarantee that every call returns a unique value for
** the lifetime of this VM. Since most platforms don't actually support
** nanosecond resolution, the unused nanoseconds are used as a counter
** to ensure uniqueness. However, bursts of calls may result in a
** drift from the actual system time. For example, if the platform's
** clock supports millisecond resolution, then calling this method
** more than one million times within a millisecond will introduce
** a millisecond drift (1,000,000ns in a ms).
**
static Int nowUnique()
**
** Make for nanosecond ticks since 1 Jan 2000 UTC. Throw
** ArgErr if ticks represent a year out of the range 1901
** to 2099.
**
static DateTime makeTicks(Int ticks, TimeZone tz := TimeZone.cur)
**
** Make for the specified date and time values:
** - year: 1901-2099
** - month: Month enumeration
** - day: 1-31
** - hour: 0-23
** - min: 0-59
** - sec: 0-59
** - ns: 0-999_999_999
** - tz: time zone used to map date/time to ns ticks
**
** Throw ArgErr if any of the parameters are out of range.
**
static new make(Int year, Month month, Int day, Int hour, Int min, Int sec := 0, Int ns := 0, TimeZone tz := TimeZone.cur)
**
** Parse the string into a DateTime from the programmatic encoding
** defined by `toStr`. If the string cannot be parsed into a valid
** DateTime and checked is false then return null, otherwise throw ParseErr.
** Also see `fromIso` and `fromHttpStr`.
**
static new fromStr(Str s, Bool checked := true)
**
** Get the boot time of the Fantom VM with `TimeZone.cur`
**
static DateTime boot()
**
** Default value is "2000-01-01T00:00:00Z UTC".
**
static const DateTime defVal
**
** Private constructor.
**
private new privateMake()
//////////////////////////////////////////////////////////////////////////
// Identity
//////////////////////////////////////////////////////////////////////////
**
** Two times are equal if they have identical nanosecond ticks.
**
override Bool equals(Obj? that)
**
** Return nanosecond ticks for the hashcode.
**
override Int hash()
**
** Compare based on nanosecond ticks.
**
override Int compare(Obj obj)
**
** Return programmatic string encoding formatted as follows:
** "YYYY-MM-DD'T'hh:mm:ss.FFFFFFFFFz zzzz"
**
** See `toLocale` for the pattern legend. The base of the
** string encoding conforms to ISO 8601 and XML Schema
** Part 2. The Fantom format also appends the timezone name to
** avoid the ambiguities associated with interpreting the time
** zone offset. Also see `toIso` and `toHttpStr`.
**
** Examples:
** "2000-04-03T00:00:00.123Z UTC"
** "2006-10-31T01:02:03-05:00 New_York"
** "2009-03-10T11:33:20Z London"
** "2009-03-01T12:00:00+01:00 Amsterdam"
**
override Str toStr()
//////////////////////////////////////////////////////////////////////////
// Access
//////////////////////////////////////////////////////////////////////////
**
** Return number of nanosecond ticks since 1 Jan 2000 UTC.
** Dates before this epoch will return a negative integer.
**
Int ticks()
**
** Get the date component of this timestamp.
**
Date date()
**
** Get the time component of this timestamp.
**
Time time()
**
** Get the year as a number such as 2007.
**
Int year()
**
** Get the month of this date.
**
Month month()
**
** Get the day of the month as a number between 1 and 31.
**
Int day()
**
** Get the hour of the time as a number between 0 and 23.
**
Int hour()
**
** Get the minutes of the time as a number between 0 and 59.
**
Int min()
**
** Get the whole seconds of the time as a number between 0 and 59.
**
Int sec()
**
** Get the number of nanoseconds (the fraction of seconds) as
** a number between 0 and 999,999,999.
**
Int nanoSec()
**
** Get the day of the week for this time.
**
Weekday weekday()
**
** Get the time zone associated with this date time.
**
TimeZone tz()
**
** Return if this time is within daylight savings time
** for its associated time zone.
**
Bool dst()
**
** Get the time zone's abbreviation for this time.
** See `TimeZone.stdAbbr` and `TimeZone.dstAbbr`.
**
Str tzAbbr()
**
** Return the day of the year as a number between
** 1 and 365 (or 1 to 366 if a leap year).
**
Int dayOfYear()
**
** Return the week number of the year as a number
** between 1 and 53 using the given weekday as the
** start of the week (defaults to current locale).
**
Int weekOfYear(Weekday startOfWeek := Weekday.localeStartOfWeek)
**
** Return the number of hours for this date and this timezone.
** Days which transition to DST will be 23 hours and days which
** transition back to standard time will be 25 hours. Note there
** is one timezone "Lord_Howe" which has a 30min offset which is
** not handled by this method (WTF).
**
Int hoursInDay()
//////////////////////////////////////////////////////////////////////////
// Locale
//////////////////////////////////////////////////////////////////////////
**
** Format this time according to the specified pattern. If
** pattern is null, then a localized default is used. Any
** ASCII letter in the pattern is interpreted as follows:
**
** YY Two digit year 07
** YYYY Four digit year 2007
** M One/two digit month 6, 11
** MM Two digit month 06, 11
** MMM Three letter abbr month Jun, Nov
** MMMM Full month June, November
** D One/two digit day 5, 28
** DD Two digit day 05, 28
** DDD Day with suffix 1st, 2nd, 3rd, 24th
** WWW Three letter abbr weekday Tue
** WWWW Full weekday Tuesday
** Q Quarter number 3
** QQQ Quarter with suffix 3rd
** QQQQ Quarter spelled out 3rd Quarter
** V One/two digit week of year 1,52
** VV Two digit week of year 01,52
** VVV Week of year with suffix 1st,52nd
** h One digit 24 hour (0-23) 3, 22
** hh Two digit 24 hour (0-23) 03, 22
** k One digit 12 hour (1-12) 3, 11
** kk Two digit 12 hour (1-12) 03, 11
** m One digit minutes (0-59) 4, 45
** mm Two digit minutes (0-59) 04, 45
** s One digit seconds (0-59) 4, 45
** ss Two digit seconds (0-59) 04, 45
** SS Optional seconds (only if non-zero)
** f* Fractional secs trailing zeros
** F* Fractional secs no trailing zeros
** a Lower case a/p for am/pm a, p
** aa Lower case am/pm am, pm
** A Upper case A/P for am/pm A, P
** AA Upper case AM/PM AM, PM
** z Time zone offset Z, +03:00 (ISO 8601, XML Schema)
** zzz Time zone abbr EST, EDT
** zzzz Time zone name New_York
** 'xyz' Literal characters
** '' Single quote literal
**
** A symbol immediately preceding a "F" pattern with no
** fraction to print is skipped.
**
** Examples:
** YYYY-MM-DD'T'hh:mm:ss.FFFz => 2009-01-16T09:57:35.097-05:00
** DD MMM YYYY => 06 Jan 2009
** DD/MMM/YY => 06/Jan/09
** MMMM D, YYYY => January 16, 2009
** hh:mm:ss.fff zzzz => 09:58:54.845 New_York
** k:mma => 9:58a
** k:mmAA => 9:58AM
**
Str toLocale(Str? pattern := null, Locale locale := Locale.cur)
**
** Parse a string into a DateTime using the given pattern. If
** string is not a valid format then return null or raise ParseErr
** based on checked flag. See `toLocale` for pattern syntax.
**
** The timezone is inferred from the zone pattern, or else the
** given 'tz' parameter is used for the timezone. The 'z' pattern
** will match "hh:mm", "hhmm", or "hh". If only a zone offset is
** available and it doesn't match the expected 'tz' parameter,
** then use a "GMT+/-" timezone. Note that if offset is a fractional
** hour such as GMT-3:30, then result will have ticks, but its
** tz will be floored hour based GMT timezone such as GMT-3.
**
static DateTime? fromLocale(Str str, Str pattern, TimeZone tz := TimeZone.cur, Bool checked := true)
//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////
**
** Convert this DateTime to the specific timezone. The absolute point
** time as ticks remains the same, but the date and time fields will
** be converted to represent the new time zone. However if converting
** to or from `TimeZone.rel` then the resulting DateTime has the same
** day and time. Also see `toUtc` and `toRel`.
**
** Example:
** dt := DateTime("2010-06-03T10:30:00-04:00 New_York")
** dt.toUtc => 2010-06-03T14:30:00Z UTC
** dt.toRel => 2010-06-03T10:30:00Z Rel
**
DateTime toTimeZone(TimeZone tz)
**
** Convenience for 'toTimeZone(TimeZone.utc)'.
**
DateTime toUtc()
**
** Convenience for 'toTimeZone(TimeZone.rel)'.
** See [docLang]`docLang::DateTime#relTimeZone`.
**
DateTime toRel()
**
** Return the delta between this and the given time.
**
** Example:
** elapsed := DateTime.now - startTime
**
@Operator Duration minusDateTime(DateTime time)
**
** Add a duration to compute a new time. This method works
** off absolute time, so adding 1days means to add 24 hours to
** the ticks. This might be a different time of day if on
** a DST boundry. Use `Date.plus` for daily increments.
**
** Example:
** nextHour := DateTime.now + 1hr
**
@Operator DateTime plus(Duration duration)
**
** Subtract a duration to compute a new time. This method works
** off absolute time, so subtracting 1days means to subtract 24
** hours from the ticks. This might be a different time of day if
** on a DST boundry. Use `Date.minus` for daily increments.
**
** Example:
** prevHour := DateTime.now - 1hr
**
@Operator DateTime minus(Duration duration)
**
** Return a new DateTime with this time's nanosecond ticks truncated
** according to the specified accuracy. For example 'floor(1min)'
** will truncate this time to the minute such that seconds
** are 0.0. This method is strictly based on absolute ticks,
** it does not take into account wall-time rollovers.
**
DateTime floor(Duration accuracy)
**
** Return a DateTime for the beginning of the current day at midnight.
**
DateTime midnight()
**
** Return if the time portion is "00:00:00".
**
Bool isMidnight()
**
** Return if the specified year is a leap year.
**
static Bool isLeapYear(Int year)
**
** This method computes the day of month (1-31) for a given
** weekday. The pos parameter specifies the first, second,
** third, or fourth occurence of the weekday. A negative pos
** is used to compute the last (or second to last, etc) weekday
** in the month.
**
** Examples:
** // compute the second monday in Apr 2007
** weekdayInMonth(2007, Month.apr, Weekday.mon, 2)
**
** // compute the last sunday in Oct 2007
** weekdayInMonth(2007, Month.oct, Weekday.sun, -1)
**
static Int weekdayInMonth(Int year, Month mon, Weekday weekday, Int pos)
//////////////////////////////////////////////////////////////////////////
// Java
//////////////////////////////////////////////////////////////////////////
**
** Create date for Java milliseconds since the epoch of 1 Jan 1970
** using the specified timezone (defaults to current). If millis
** are less than or equal to zero then return null or a date before
** 1970 depending on the 'negIsNull' flag.
**
static DateTime? fromJava(Int millis, TimeZone tz := TimeZone.cur, Bool negIsNull := true)
**
** Get this date in Java milliseconds since the epoch of 1 Jan 1970.
**
Int toJava()
//////////////////////////////////////////////////////////////////////////
// ISO 8601
//////////////////////////////////////////////////////////////////////////
**
** Parse an ISO 8601 timestamp. If invalid format and checked is
** false return null, otherwise throw ParseErr. The following formats
** are supported:
** YYYY-MM-DD'T'hh:mm:ss[.FFFFFFFFF]
** YYYY-MM-DD'T'hh:mm:ss[.FFFFFFFFF]+HH:MM
** YYYY-MM-DD'T'hh:mm:ss[.FFFFFFFFF]-HH:MM
**
** If a timezone offset is specified, then one of the predefined "Etc/GMT+x"
** timezones are used for the result:
** DateTime("2009-01-15T12:00:00Z") => 2009-01-15T12:00:00Z UTC
** DateTime("2009-01-15T12:00:00-05:00") => 2009-01-15T12:00:00-05:00 GMT+5
**
** Also see `toIso`, `fromStr`, and `fromHttpStr`.
**
static DateTime? fromIso(Str s, Bool checked := true)
**
** Format this instance according to ISO 8601 using the pattern:
** YYYY-MM-DD'T'hh:mm:ss.FFFz
**
** Also see `fromIso`, `toStr`, and `toHttpStr`.
**
Str toIso()
//////////////////////////////////////////////////////////////////////////
// HTTP
//////////////////////////////////////////////////////////////////////////
**
** Parse an HTTP date according to the RFC 2616 section 3.3.1. If
** invalid format and checked is false return null, otherwise
** throw ParseErr. The following date formats are supported:
**
** Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
** Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
** Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
**
static DateTime? fromHttpStr(Str s, Bool checked := true)
**
** Format this time for use in an MIME or HTTP message
** according to RFC 2616 using the RFC 1123 format:
**
** Sun, 06 Nov 1994 08:49:37 GMT
**
Str toHttpStr()
//////////////////////////////////////////////////////////////////////////
// Misc
//////////////////////////////////////////////////////////////////////////
**
** Get this DateTime as a Fantom expression suitable for code generation.
**
Str toCode()
}