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.

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.

More...
SysTime
parse
(
Range
)
(,
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
&&
isSomeChar!(ElementEncodingType!Range)
)

Parameters

timeString Range

A forward range containing a date/time stamp.

ignoreTimezone Flag!"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 const(TimeZone)[string]

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 Flag!"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 Flag!"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 Flag!"fuzzy"

Whether to allow fuzzy parsing, allowing for string like "Today is January 1, 2047 at 8:21:00AM".

defaultDate SysTime

The date to apply the given information on top of. Defaults to January 1st, 1 AD

Return Value

Type: SysTime

A SysTime object representing the parsed string

Detailed Description

Unicode Specifics

  1. The AA key comparisons done with ParserInfo are on a code unit by code unit basis. As such, if user data passed to this function has a different normalization than the AAs in the used ParserInfo class, then you will get parser exceptions.
  2. 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 and expects ASCII numbers.

Throws

ConvException will be thrown for invalid string or unknown string format

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

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

Examples

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)));

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)));

Custom allocators

import std.experimental.allocator.mallocator : Mallocator;

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

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("01-Jane-01"));
assertThrown!ConvException(parse("13:44 AM"));
assertThrown!ConvException(parse("January 25, 1921 23:13 PM"));

Custom parser info allows for international time representation

import std.utf : byChar;

class RusParserInfo : ParserInfo
{
    this()
    {
        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)));

immutable parsedTime2 = rusParser.parse("10 Сентябрь 2015 10:20"d.byChar);
assert(parsedTime2 == SysTime(DateTime(2015, 9, 10, 10, 20)));

Meta