0

I am developing an application that should accept arbitrarily formatted dates -- in other words, if it walks like date, talks like a date, it's a date.

I have attempted to adapt the date format parser from the moment.js package to generate a format string with some partial success but have run into a situation where the input string in it has some element that is not recognized.

For instance, there seems to be no proper format to deal with the string

Thu Nov 07 2019 13:50:03 GMT-0800 (PST)

-- or, at least one which seems clear to me but perhaps I'm missing something in the documentation.

I have looked at https://pub.dev/documentation/intl/latest/intl/DateFormat-class.html but I see no way of, for instance, ignoring fields that may be irrelevant or encoding the format correctly (for instance the GMT-0800 field).

I am using the jiffy package to do the date parsing if that matters.

Following up: I suspect what I'm looking for is something that acts more or less like strptime() in the C language. Or maybe not.

3 Answers3

0

if it walks like date, talks like a date, it's a date

The Problem is that there is no such way to walk or such a date.

Dates are a hassle to implement properly in any language, as there are no rules defining exactly how a date should be formatted by human beings. The "arbitrarily formatted dates" you're asking for, well, they wouldn't be worth much as they wouldn't represent actual dates in a predictable manner. Check out the latest date/time related questions here on SO to get a perspective!

Using the the Dart DateTime class, you can only create a DateTime object by parsing a correctly formatted string which complies with a subset of ISO 8601

How you get to such a string from "arbitrary" input must be defined by you.

You can use some pre-defined constants to improve code readability, but using the DateTime class directly would require you to write some pretty cool code for extracting and formatting any possible perception of a date anywhere in the world into the correct syntax for creating a usable DateTime object. Maybe create a Date Input AI!

Luckily you can do a lot of heavy lifting using the class you mentioned: DateFormat Class, which is the way I would attack this.

It has ways to help you format localized date strings from input, then, together with some regular expressions you should be able to achieve what you need if you validate this based on "sane value ranges" for your application domain.

But the exact logic is something you'd be better off creating yourself, as this would vary from case to case / app to app.

C. Sederqvist
  • 2,830
  • 19
  • 27
  • Thanx. As I mentioned, I've sort of ported the date format generator for moment.js, which generates a format string which can then be applied to the string in question to cough up a DateTime object as a reward for your efforts. What I was missing (and indeed missed in the documentation) was a text escape for unparsed literals. Encapsulating GMT-0800 in 'GMT-0800', along with a little extra logic in the parser, did the job. – Teakwood J Overclutch Sep 30 '20 at 17:57
0

The basic answer, as I mentioned in the comment to cseder was to encapsulate the uninteresting tokens of the date string in single quotes, per the documentation.

For instance, the format

EEE MMM DD yyyy H:mm:ss 'GMT-0800' '(PST)'

happily parses the string

Thu Nov 07 2019 13:50:03 GMT-0800 (PST)

I can probably also deal with the timezone issues but this reqolves the immediate question.

  • Yeah, based on a simplified, artificial, custom tailored reality, this would be sufficient. – C. Sederqvist Oct 10 '20 at 23:33
  • And what is programming but a "simplified, artificial, custom tailored reality?" I apologize for any offense given. – Teakwood J Overclutch Oct 12 '20 at 00:23
  • Well, it is and it isn't. It is in that it deals with the specific instance within the specific context of the specific problem, which was to deal with that particular string. It isn't in that it obviously does not deal with the entire universe of free form date parsing, which I fullly acknowledged in another comment. I have other thoughts on the subject, including Dart's approach to date/time handling, but they are probably better reserved for some other forum. – Teakwood J Overclutch Oct 13 '20 at 12:20
0

There are a number of ways to parse different timestamp formats. But note that accepting completely arbitrary formats can be ambiguous: does 01-02-2020 represent January 2, 2020 (typical U.S. convention) or February 1, 2020 (most other parts of the world)?

In the particular case you describe, I would break up the string with a RegExp first (or from .split(' ')) to separate the bits that DateFormat can handle (basically everything other than time zones, which DateFormat doesn't support). While you could use DateFormat's mechanism for escaping literal text to ignore the time zone, that would work only if the time zone is guaranteed to never change. Even if the strings come from a server in a fixed location, GMT-0800 (PST) might change to GMT-0700 (PDT) if daylight saving time was in effect.

The timezone itself you could parse manually with a RegExp, or you could use TZDateTime.parse from package:timezone.

I believe that the following code should parse the string as a UTC DateTime object:

DateTime parseDate(String timestamp) {
  final re = RegExp(''
      r'^(?<datetime>\w{3} \w{3} \d{2} \d{4} \d{2}:\d{2}:\d{2}) '
      r'\w{3}(?<offset>[+-]\d{4}) '
      r'.*$');
  final match = re.firstMatch(timestamp);
  if (match == null) {
    throw FormatException('Failed to parse timestamp: $timestamp');
  }

  final rawOffsetFromGMT = int.parse(match.namedGroup('offset'));
  final offsetFromGMT = Duration(
    hours: rawOffsetFromGMT ~/ 100,
    minutes: rawOffsetFromGMT.remainder(100),
  );

  return DateFormat('EEE MMM DD yyyy H:mm:ss')
      .parse(
        match.namedGroup('datetime'),
        true,
      )
      .subtract(offsetFromGMT);
}

void main() {
  print(parseDate('Thu Nov 07 2019 13:50:03 GMT-0800 (PST)'));
}
jamesdlin
  • 81,374
  • 13
  • 159
  • 204
  • Thanks. I fully understand the ambiguities in date parsing. Believe me, I have the battle scars to prove it. My issue was simply that I'd missed an essential point in the documentation about string escapes and, yes, I recognize that it's not a general solution -- it just got me over an immediate hump and I'll have to circle back and make some further additions to the code later on. – Teakwood J Overclutch Sep 30 '20 at 22:55