Function parse

This function offers a generic date/time string Parser which is able to parse most known formats to represent a date and/or time.

This function attempts to be forgiving with regards to unlikely input formats, returning a SysTime object even for dates which are ambiguous. While other languages have writing systems without Arabic numerals, the overwhelming majority of dates are written with them. As such, this function does not work with other number systems.

If an element of a date/time stamp is omitted, the following rules are applied:

  • If AM or PM is left unspecified, a 24-hour clock is assumed, however, an hour on a 12-hour clock (0 <= hour <= 12) *must* be specified if AM or PM is specified.
  • If a time zone is omitted, a SysTime is given with the timezone of the host machine.

Missing information is allowed, and what ever is given is applied on top of the defaultDate parameter, which defaults to January 1, 1 AD at midnight. E.g. a string of "10:00 AM" with a defaultDate of SysTime(Date(2016, 1, 1)) will yield SysTime(DateTime(2016, 1, 1, 10, 0, 0)).

If your date string uses timezone names in place of UTC offsets, then timezone information must be user provided, as there is no way to reliably get timezones from the OS by abbreviation. But, the timezone will be properly set if an offset is given. Timezone info and their abbreviations change constantly, so it's a good idea to not rely on timezoneInfos too much.

This function allocates memory and throws on the GC. In order to reduce GC allocations, use a custom Parser instance with a different allocator.

Prototype

SysTime parse(Range)(
  Range timeString,
  Flag!"ignoreTimezone" ignoreTimezone = No.ignoreTimezone,
  const(TimeZone)[string] timezoneInfos = null,
  Flag!"dayFirst" dayFirst = No.dayFirst,
  Flag!"yearFirst" yearFirst = No.yearFirst,
  Flag!"fuzzy" fuzzy = No.fuzzy,
  SysTime defaultDate = SysTime(DateTime(1, 1, 1))
)
if (isForwardRange!Range && !isInfinite!Range && is(Unqual!(ElementEncodingType!Range) : char));

Parameters

NameDescription
timeString A forward range with UTF-8 encoded elements containing a date/time stamp.
ignoreTimezone Set to false by default, time zones in parsed strings are ignored and a SysTime with the local time zone is returned. If timezone information is not important, setting this to true is slightly faster.
timezoneInfos Time zone names / aliases which may be present in the string. This argument maps time zone names (and optionally offsets from those time zones) to time zones. This parameter is ignored if ignoreTimezone is set.
dayFirst Whether to interpret the first value in an ambiguous 3-integer date (e.g. 01/05/09) as the day (true) or month (false). If yearFirst is set to true, this distinguishes between YDM and YMD.
yearFirst Whether to interpret the first value in an ambiguous 3-integer date (e.g. 01/05/09) as the year. If true, the first number is taken to be the year, otherwise the last number is taken to be the year.
fuzzy Whether to allow fuzzy parsing, allowing for string like "Today is January 1, 2047 at 8:21:00AM".
defaultDate The date to apply the given information on top of. Defaults to January 1st, 1 AD

Returns

A SysTime object representing the parsed string

Throws

ConvException will be thrown for invalid string or unknown string format

Throws

TimeException if the date string is successfully parsed but the created date would be invalid

Throws

ConvOverflowException if one of the numbers in the parsed date exceeds float.max

Example

immutable brazilTime = new SimpleTimeZone(dur!"seconds"(-10_800));
const(TimeZone)[string] timezones = ["BRST" : brazilTime];

immutable parsed = parse("Thu Sep 25 10:36:28 BRST 2003", No.ignoreTimezone, timezones);
// SysTime opEquals ignores timezones
assert(parsed == SysTime(DateTime(2003, 9, 25, 10, 36, 28)));
assert(parsed.timezone == brazilTime);

assert(parse(
    "2003 10:36:28 BRST 25 Sep Thu",
    No.ignoreTimezone,
    timezones
) == SysTime(DateTime(2003, 9, 25, 10, 36, 28)));
assert(parse("Thu Sep 25 10:36:28") == SysTime(DateTime(1, 9, 25, 10, 36, 28)));
assert(parse("20030925T104941") == SysTime(DateTime(2003, 9, 25, 10, 49, 41)));
assert(parse("2003-09-25T10:49:41") == SysTime(DateTime(2003, 9, 25, 10, 49, 41)));
assert(parse("10:36:28") == SysTime(DateTime(1, 1, 1, 10, 36, 28)));
assert(parse("09-25-2003") == SysTime(DateTime(2003, 9, 25)));

Example

Apply information on top of defaultDate

assert("10:36:28".parse(No.ignoreTimezone, null, No.dayFirst, No.yearFirst,
    No.fuzzy, SysTime(DateTime(2016, 3, 15)))
== SysTime(DateTime(2016, 3, 15, 10, 36, 28)));
assert("August 07".parse(No.ignoreTimezone, null, No.dayFirst, No.yearFirst,
    No.fuzzy, SysTime(DateTime(2016, 1, 1)))
== SysTime(Date(2016, 8, 7)));
assert("2000".parse(No.ignoreTimezone, null, No.dayFirst, No.yearFirst,
    No.fuzzy, SysTime(DateTime(2016, 3, 1)))
== SysTime(Date(2000, 3, 1)));

Example

Custom allocators

import std.experimental.allocator.mallocator;

auto customParser = new Parser!Mallocator(new ParserInfo());
assert(customParser.parse("2003-09-25T10:49:41") ==
    SysTime(DateTime(2003, 9, 25, 10, 49, 41)));

Example

Exceptions

import std.exception : assertThrown;
import std.conv : ConvException;

assertThrown!ConvException(parse(""));
assertThrown!ConvException(parse("AM"));
assertThrown!ConvException(parse("The quick brown fox jumps over the lazy dog"));
assertThrown!TimeException(parse("Feb 30, 2007"));
assertThrown!TimeException(parse("Jan 20, 2015 PM"));
assertThrown!ConvException(parse("13:44 AM"));
assertThrown!ConvException(parse("January 25, 1921 23:13 PM"));

Example

Custom parser info allows for international time representation

class RusParserInfo : ParserInfo
{
    this()
    {
        super(false, false);
        monthsAA = ParserInfo.convert([
            ["янв", "Январь"],
            ["фев", "Февраль"],
            ["мар", "Март"],
            ["апр", "Апрель"],
            ["май", "Май"],
            ["июн", "Июнь"],
            ["июл", "Июль"],
            ["авг", "Август"],
            ["сен", "Сентябрь"],
            ["окт", "Октябрь"],
            ["ноя", "Ноябрь"],
            ["дек", "Декабрь"]
        ]);
    }
}

auto rusParser = new Parser!GCAllocator(new RusParserInfo());
immutable parsedTime = rusParser.parse("10 Сентябрь 2015 10:20");
assert(parsedTime == SysTime(DateTime(2015, 9, 10, 10, 20)));

Authors

Copyright

License