Created
October 13, 2011 00:10
-
-
Save JesseKPhillips/1283011 to your computer and use it in GitHub Desktop.
std.dateparse braught to use std.datetime
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Written in the D programming language. | |
/** | |
* $(RED Deprecated. It will be removed in February 2012. | |
* Please use std.datetime instead.) | |
* | |
* dateparse module. | |
* | |
* Copyright: Copyright Digital Mars 2000 - 2009. | |
* License: <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>. | |
* Authors: $(WEB digitalmars.com, Walter Bright) | |
* Source: $(PHOBOSSRC std/_dateparse.d) | |
*/ | |
/* | |
* Copyright Digital Mars 2000 - 2009. | |
* Distributed under the Boost Software License, Version 1.0. | |
* (See accompanying file LICENSE_1_0.txt or copy at | |
* http://www.boost.org/LICENSE_1_0.txt) | |
*/ | |
module dateparse; | |
private | |
{ | |
import std.algorithm, std.string; | |
import std.c.stdlib; | |
import std.datetime; | |
} | |
//debug=dateparse; | |
class DateParseException : Exception | |
{ | |
this(string s) | |
{ | |
super("Invalid date string: " ~ s); | |
} | |
} | |
auto dateParse(string s, out SysTime date) { | |
DateParse dp; | |
dp.parse(s, date); | |
return date; | |
} | |
struct DateParse | |
{ | |
void parse(string s, out SysTime date) | |
{ | |
this = DateParse.init; | |
//version (Win32) | |
buffer = (cast(char *)alloca(s.length))[0 .. s.length]; | |
//else | |
//buffer = new char[s.length]; | |
debug(dateparse) printf("DateParse.parse('%.*s')\n", s); | |
if (!parseString(s)) | |
{ | |
goto Lerror; | |
} | |
/+ | |
if (year == year.init) | |
year = 0; | |
else | |
+/ | |
debug(dateparse) | |
printf("year = %d, month = %d, day = %d\n%02d:%02d:%02d.%03d\nweekday = %d, tzcorrection = %d\n", | |
year, month, day, | |
hours, minutes, seconds, ms, | |
weekday, tzcorrection); | |
if ( | |
year == year.init || | |
(month < 1 || month > 12) || | |
(day < 1 || day > 31) || | |
(hours < 0 || hours > 23) || | |
(minutes < 0 || minutes > 59) || | |
(seconds < 0 || seconds > 59) || | |
(tzcorrection != int.min && | |
((tzcorrection < -2300 || tzcorrection > 2300) || | |
(tzcorrection % 10))) | |
) | |
{ | |
Lerror: | |
throw new DateParseException(s); | |
} | |
if (ampm) | |
{ if (hours > 12) | |
goto Lerror; | |
if (hours < 12) | |
{ | |
if (ampm == 2) // if P.M. | |
hours += 12; | |
} | |
else if (ampm == 1) // if 12am | |
{ | |
hours = 0; // which is midnight | |
} | |
} | |
// if (tzcorrection != tzcorrection.init) | |
// tzcorrection /= 100; | |
if (year >= 0 && year <= 99) | |
year += 1900; | |
if(tzcorrection == int.min) | |
date = SysTime(DateTime(year,month,day,hours,minutes,seconds), | |
FracSec.from!"msecs"(ms)); | |
else { | |
auto tz = | |
new SimpleTimeZone(tzcorrection/100*60+tzcorrection%100); | |
date = SysTime(DateTime(year,month,day,hours,minutes,seconds), | |
FracSec.from!"msecs"(ms), tz); | |
} | |
debug(dateparse) printf("year = %d, month = %d, day = %d\n%02d:%02d:%02d.%03d\ntzcorrection = %d\n", | |
date.year, date.month, date.day, | |
date.hour, date.minute, date.second, date.fracSec, | |
date.timezone); | |
} | |
private: | |
int year = int.min; // our "nan" Date value | |
Month month; // 1..12 | |
int day; // 1..31 | |
int hours; // 0..23 | |
int minutes; // 0..59 | |
int seconds; // 0..59 | |
int ms; // 0..999 | |
int weekday; // 1..7 | |
int ampm; // 0: not specified | |
// 1: AM | |
// 2: PM | |
int tzcorrection = int.min; // -1200..1200 correction in hours | |
string s; | |
int si; | |
int number; | |
char[] buffer; | |
enum DP : byte | |
{ | |
err, | |
weekday, | |
month, | |
number, | |
end, | |
colon, | |
minus, | |
slash, | |
ampm, | |
plus, | |
tz, | |
dst, | |
dsttz, | |
} | |
DP nextToken() | |
{ int nest; | |
uint c; | |
int bi; | |
DP result = DP.err; | |
//printf("DateParse::nextToken()\n"); | |
for (;;) | |
{ | |
assert(si <= s.length); | |
if (si == s.length) | |
{ result = DP.end; | |
goto Lret; | |
} | |
//printf("\ts[%d] = '%c'\n", si, s[si]); | |
switch (s[si]) | |
{ | |
case ':': result = DP.colon; goto ret_inc; | |
case '+': result = DP.plus; goto ret_inc; | |
case '-': result = DP.minus; goto ret_inc; | |
case '/': result = DP.slash; goto ret_inc; | |
case '.': | |
version(DATE_DOT_DELIM) | |
{ | |
result = DP.slash; | |
goto ret_inc; | |
} | |
else | |
{ | |
si++; | |
break; | |
} | |
ret_inc: | |
si++; | |
goto Lret; | |
case ' ': | |
case '\n': | |
case '\r': | |
case '\t': | |
case ',': | |
si++; | |
break; | |
case '(': // comment | |
nest = 1; | |
for (;;) | |
{ | |
si++; | |
if (si == s.length) | |
goto Lret; // error | |
switch (s[si]) | |
{ | |
case '(': | |
nest++; | |
break; | |
case ')': | |
if (--nest == 0) | |
goto Lendofcomment; | |
break; | |
default: | |
break; | |
} | |
} | |
Lendofcomment: | |
si++; | |
break; | |
default: | |
number = 0; | |
for (;;) | |
{ | |
if (si == s.length) | |
// c cannot be undefined here | |
break; | |
c = s[si]; | |
if (!(c >= '0' && c <= '9')) | |
break; | |
result = DP.number; | |
number = number * 10 + (c - '0'); | |
si++; | |
} | |
if (result == DP.number) | |
goto Lret; | |
bi = 0; | |
bufloop: | |
while (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z') | |
{ | |
if (c < 'a') // if upper case | |
c += cast(uint)'a' - cast(uint)'A'; // to lower case | |
buffer[bi] = cast(char)c; | |
bi++; | |
do | |
{ | |
si++; | |
if (si == s.length) | |
break bufloop; | |
c = s[si]; | |
} while (c == '.'); // ignore embedded '.'s | |
} | |
result = classify(buffer[0 .. bi].idup); | |
goto Lret; | |
} | |
} | |
Lret: | |
//printf("-DateParse::nextToken()\n"); | |
return result; | |
} | |
DP classify(string buf) | |
{ | |
struct DateID | |
{ | |
string name; | |
DP tok; | |
short value; | |
} | |
static immutable DateID dateidtab[] = | |
[ | |
{ "january", DP.month, 1}, | |
{ "february", DP.month, 2}, | |
{ "march", DP.month, 3}, | |
{ "april", DP.month, 4}, | |
{ "may", DP.month, 5}, | |
{ "june", DP.month, 6}, | |
{ "july", DP.month, 7}, | |
{ "august", DP.month, 8}, | |
{ "september", DP.month, 9}, | |
{ "october", DP.month, 10}, | |
{ "november", DP.month, 11}, | |
{ "december", DP.month, 12}, | |
{ "jan", DP.month, 1}, | |
{ "feb", DP.month, 2}, | |
{ "mar", DP.month, 3}, | |
{ "apr", DP.month, 4}, | |
{ "jun", DP.month, 6}, | |
{ "jul", DP.month, 7}, | |
{ "aug", DP.month, 8}, | |
{ "sep", DP.month, 9}, | |
{ "sept", DP.month, 9}, | |
{ "oct", DP.month, 10}, | |
{ "nov", DP.month, 11}, | |
{ "dec", DP.month, 12}, | |
{ "sunday", DP.weekday, 1}, | |
{ "monday", DP.weekday, 2}, | |
{ "tuesday", DP.weekday, 3}, | |
{ "tues", DP.weekday, 3}, | |
{ "wednesday", DP.weekday, 4}, | |
{ "wednes", DP.weekday, 4}, | |
{ "thursday", DP.weekday, 5}, | |
{ "thur", DP.weekday, 5}, | |
{ "thurs", DP.weekday, 5}, | |
{ "friday", DP.weekday, 6}, | |
{ "saturday", DP.weekday, 7}, | |
{ "sun", DP.weekday, 1}, | |
{ "mon", DP.weekday, 2}, | |
{ "tue", DP.weekday, 3}, | |
{ "wed", DP.weekday, 4}, | |
{ "thu", DP.weekday, 5}, | |
{ "fri", DP.weekday, 6}, | |
{ "sat", DP.weekday, 7}, | |
{ "am", DP.ampm, 1}, | |
{ "pm", DP.ampm, 2}, | |
{ "gmt", DP.tz, +000}, | |
{ "ut", DP.tz, +000}, | |
{ "utc", DP.tz, +000}, | |
{ "wet", DP.tz, +000}, | |
{ "z", DP.tz, +000}, | |
{ "wat", DP.tz, +100}, | |
{ "a", DP.tz, +100}, | |
{ "at", DP.tz, +200}, | |
{ "b", DP.tz, +200}, | |
{ "c", DP.tz, +300}, | |
{ "ast", DP.tz, +400}, | |
{ "d", DP.tz, +400}, | |
{ "est", DP.tz, +500}, | |
{ "e", DP.tz, +500}, | |
{ "cst", DP.tz, +600}, | |
{ "f", DP.tz, +600}, | |
{ "mst", DP.tz, +700}, | |
{ "g", DP.tz, +700}, | |
{ "pst", DP.tz, +800}, | |
{ "h", DP.tz, +800}, | |
{ "yst", DP.tz, +900}, | |
{ "i", DP.tz, +900}, | |
{ "ahst", DP.tz, +1000}, | |
{ "cat", DP.tz, +1000}, | |
{ "hst", DP.tz, +1000}, | |
{ "k", DP.tz, +1000}, | |
{ "nt", DP.tz, +1100}, | |
{ "l", DP.tz, +1100}, | |
{ "idlw", DP.tz, +1200}, | |
{ "m", DP.tz, +1200}, | |
{ "cet", DP.tz, -100}, | |
{ "fwt", DP.tz, -100}, | |
{ "met", DP.tz, -100}, | |
{ "mewt", DP.tz, -100}, | |
{ "swt", DP.tz, -100}, | |
{ "n", DP.tz, -100}, | |
{ "eet", DP.tz, -200}, | |
{ "o", DP.tz, -200}, | |
{ "bt", DP.tz, -300}, | |
{ "p", DP.tz, -300}, | |
{ "zp4", DP.tz, -400}, | |
{ "q", DP.tz, -400}, | |
{ "zp5", DP.tz, -500}, | |
{ "r", DP.tz, -500}, | |
{ "zp6", DP.tz, -600}, | |
{ "s", DP.tz, -600}, | |
{ "wast", DP.tz, -700}, | |
{ "t", DP.tz, -700}, | |
{ "cct", DP.tz, -800}, | |
{ "u", DP.tz, -800}, | |
{ "jst", DP.tz, -900}, | |
{ "v", DP.tz, -900}, | |
{ "east", DP.tz, -1000}, | |
{ "gst", DP.tz, -1000}, | |
{ "w", DP.tz, -1000}, | |
{ "x", DP.tz, -1100}, | |
{ "idle", DP.tz, -1200}, | |
{ "nzst", DP.tz, -1200}, | |
{ "nzt", DP.tz, -1200}, | |
{ "y", DP.tz, -1200}, | |
{ "bst", DP.dsttz, 000}, | |
{ "adt", DP.dsttz, +400}, | |
{ "edt", DP.dsttz, +500}, | |
{ "cdt", DP.dsttz, +600}, | |
{ "mdt", DP.dsttz, +700}, | |
{ "pdt", DP.dsttz, +800}, | |
{ "ydt", DP.dsttz, +900}, | |
{ "hdt", DP.dsttz, +1000}, | |
{ "mest", DP.dsttz, -100}, | |
{ "mesz", DP.dsttz, -100}, | |
{ "sst", DP.dsttz, -100}, | |
{ "fst", DP.dsttz, -100}, | |
{ "wadt", DP.dsttz, -700}, | |
{ "eadt", DP.dsttz, -1000}, | |
{ "nzdt", DP.dsttz, -1200}, | |
{ "dst", DP.dst, 0}, | |
]; | |
//message(DTEXT("DateParse::classify('%s')\n"), buf); | |
// Do a linear search. Yes, it would be faster with a binary | |
// one. | |
for (uint i = 0; i < dateidtab.length; i++) | |
{ | |
if (cmp(dateidtab[i].name, buf) == 0) | |
{ | |
number = dateidtab[i].value; | |
return dateidtab[i].tok; | |
} | |
} | |
return DP.err; | |
} | |
int parseString(string s) | |
{ | |
int n1; | |
int dp; | |
int sisave; | |
int result; | |
//message(DTEXT("DateParse::parseString('%ls')\n"), s); | |
this.s = s; | |
si = 0; | |
dp = nextToken(); | |
for (;;) | |
{ | |
//message(DTEXT("\tdp = %d\n"), dp); | |
switch (dp) | |
{ | |
case DP.end: | |
result = 1; | |
Lret: | |
return result; | |
case DP.err: | |
case_error: | |
//message(DTEXT("\terror\n")); | |
default: | |
result = 0; | |
goto Lret; | |
case DP.minus: | |
break; // ignore spurious '-' | |
case DP.weekday: | |
weekday = number; | |
break; | |
case DP.month: // month day, [year] | |
month = cast(Month)(number); | |
dp = nextToken(); | |
if (dp == DP.number) | |
{ | |
day = number; | |
sisave = si; | |
dp = nextToken(); | |
if (dp == DP.number) | |
{ | |
n1 = number; | |
dp = nextToken(); | |
if (dp == DP.colon) | |
{ // back up, not a year | |
si = sisave; | |
} | |
else | |
{ year = n1; | |
continue; | |
} | |
break; | |
} | |
} | |
continue; | |
case DP.number: | |
n1 = number; | |
dp = nextToken(); | |
switch (dp) | |
{ | |
case DP.end: | |
year = n1; | |
break; | |
case DP.minus: | |
case DP.slash: // n1/ ? ? ? | |
dp = parseCalendarDate(n1); | |
if (dp == DP.err) | |
goto case_error; | |
break; | |
case DP.colon: // hh:mm [:ss] [am | pm] | |
dp = parseTimeOfDay(n1); | |
if (dp == DP.err) | |
goto case_error; | |
break; | |
case DP.ampm: | |
hours = n1; | |
minutes = 0; | |
seconds = 0; | |
ampm = number; | |
break; | |
case DP.month: | |
day = n1; | |
month = cast(Month)(number); | |
dp = nextToken(); | |
if (dp == DP.number) | |
{ // day month year | |
year = number; | |
dp = nextToken(); | |
} | |
break; | |
default: | |
year = n1; | |
break; | |
} | |
continue; | |
} | |
dp = nextToken(); | |
} | |
// @@@ bug in the compiler: this is never reachable | |
assert(0); | |
} | |
int parseCalendarDate(int n1) | |
{ | |
int n2; | |
int n3; | |
int dp; | |
debug(dateparse) printf("DateParse.parseCalendarDate(%d)\n", n1); | |
dp = nextToken(); | |
if (dp == DP.month) // day/month | |
{ | |
day = n1; | |
month = cast(Month)(number); | |
dp = nextToken(); | |
if (dp == DP.number) | |
{ // day/month year | |
year = number; | |
dp = nextToken(); | |
} | |
else if (dp == DP.minus || dp == DP.slash) | |
{ // day/month/year | |
dp = nextToken(); | |
if (dp != DP.number) | |
goto case_error; | |
year = number; | |
dp = nextToken(); | |
} | |
return dp; | |
} | |
if (dp != DP.number) | |
goto case_error; | |
n2 = number; | |
//message(DTEXT("\tn2 = %d\n"), n2); | |
dp = nextToken(); | |
if (dp == DP.minus || dp == DP.slash) | |
{ | |
dp = nextToken(); | |
if (dp != DP.number) | |
goto case_error; | |
n3 = number; | |
//message(DTEXT("\tn3 = %d\n"), n3); | |
dp = nextToken(); | |
// case1: year/month/day | |
// case2: month/day/year | |
int case1, case2; | |
case1 = (n1 > 12 || | |
(n2 >= 1 && n2 <= 12) && | |
(n3 >= 1 && n3 <= 31)); | |
case2 = ((n1 >= 1 && n1 <= 12) && | |
(n2 >= 1 && n2 <= 31) || | |
n3 > 31); | |
if (case1 == case2) | |
goto case_error; | |
if (case1) | |
{ | |
year = n1; | |
month = cast(Month) (n2); | |
day = n3; | |
} | |
else | |
{ | |
month = cast(Month) (n1); | |
day = n2; | |
year = n3; | |
} | |
} | |
else | |
{ // must be month/day | |
month = cast(Month) (n1); | |
day = n2; | |
} | |
return dp; | |
case_error: | |
return DP.err; | |
} | |
int parseTimeOfDay(int n1) | |
{ | |
int dp; | |
int sign; | |
// 12am is midnight | |
// 12pm is noon | |
//message(DTEXT("DateParse::parseTimeOfDay(%d)\n"), n1); | |
hours = n1; | |
dp = nextToken(); | |
if (dp != DP.number) | |
goto case_error; | |
minutes = number; | |
dp = nextToken(); | |
if (dp == DP.colon) | |
{ | |
dp = nextToken(); | |
if (dp != DP.number) | |
goto case_error; | |
seconds = number; | |
dp = nextToken(); | |
} | |
else | |
seconds = 0; | |
if (dp == DP.ampm) | |
{ | |
ampm = number; | |
dp = nextToken(); | |
} | |
else if (dp == DP.plus || dp == DP.minus) | |
{ | |
Loffset: | |
sign = (dp == DP.minus) ? -1 : 1; | |
dp = nextToken(); | |
if (dp != DP.number) | |
goto case_error; | |
tzcorrection = -sign * number; | |
dp = nextToken(); | |
} | |
else if (dp == DP.tz) | |
{ | |
tzcorrection = number; | |
dp = nextToken(); | |
if (number == 0 && (dp == DP.plus || dp == DP.minus)) | |
goto Loffset; | |
if (dp == DP.dst) | |
{ tzcorrection += 100; | |
dp = nextToken(); | |
} | |
} | |
else if (dp == DP.dsttz) | |
{ | |
tzcorrection = number; | |
dp = nextToken(); | |
} | |
return dp; | |
case_error: | |
return DP.err; | |
} | |
} | |
unittest | |
{ | |
DateParse dp; | |
SysTime d; | |
import std.stdio; | |
import std.conv; | |
dp.parse("March 10, 1959 12:00 -800", d); | |
assert(d.year == 1959); | |
assert(d.month == Month.mar); | |
assert(d.day == 10); | |
assert(d.hour == 12); | |
assert(d.minute == 0); | |
assert(d.second == 0); | |
assert(d.fracSec == FracSec.from!"msecs"(0)); | |
//assert(d.timezone == new SimpleTimeZone(-800)); | |
dp.parse("Tue Apr 02 02:04:57 GMT-0800 1996", d); | |
assert(d.year == 1996); | |
assert(d.month == 4); | |
assert(d.day == 2); | |
assert(d.hour == 2); | |
assert(d.minute == 4); | |
assert(d.second == 57); | |
assert(d.fracSec == FracSec.from!"msecs"(0)); | |
//assert(d.timezone == new SimpleTimeZone(-800)); | |
dp.parse("March 14, -1980 21:14:50", d); | |
assert(d.year == 1980); | |
assert(d.month == 3); | |
assert(d.day == 14); | |
assert(d.hour == 21); | |
assert(d.minute == 14); | |
assert(d.second == 50); | |
assert(d.fracSec == FracSec.from!"msecs"(0)); | |
//assert(d.timezone == new SimpleTimeZone(int.min)); | |
dp.parse("Tue Apr 02 02:04:57 1996", d); | |
assert(d.year == 1996); | |
assert(d.month == 4); | |
assert(d.day == 2); | |
assert(d.hour == 2); | |
assert(d.minute == 4); | |
assert(d.second == 57); | |
assert(d.fracSec == FracSec.from!"msecs"(0)); | |
//assert(d.timezone == new SimpleTimeZone(int.min)); | |
dp.parse("Tue, 02 Apr 1996 02:04:57 G.M.T.", d); | |
assert(d.year == 1996); | |
assert(d.month == 4); | |
assert(d.day == 2); | |
assert(d.hour == 2); | |
assert(d.minute == 4); | |
assert(d.second == 57); | |
assert(d.fracSec == FracSec.from!"msecs"(0)); | |
//assert(d.timezone == new SimpleTimeZone(0)); | |
dp.parse("December 31, 3000", d); | |
assert(d.year == 3000); | |
assert(d.month == 12); | |
assert(d.day == 31); | |
assert(d.hour == 0); | |
assert(d.minute == 0); | |
assert(d.second == 0); | |
assert(d.fracSec == FracSec.from!"msecs"(0)); | |
//assert(d.timezone == new SimpleTimeZone(int.min)); | |
dp.parse("Wed, 31 Dec 1969 16:00:00 GMT", d); | |
assert(d.year == 1969); | |
assert(d.month == 12); | |
assert(d.day == 31); | |
assert(d.hour == 16); | |
assert(d.minute == 0); | |
assert(d.second == 0); | |
assert(d.fracSec == FracSec.from!"msecs"(0)); | |
//assert(d.timezone == new SimpleTimeZone(0)); | |
dp.parse("1/1/1999 12:30 AM", d); | |
assert(d.year == 1999); | |
assert(d.month == 1); | |
assert(d.day == 1); | |
assert(d.hour == 0); | |
assert(d.minute == 30); | |
assert(d.second == 0); | |
assert(d.fracSec == FracSec.from!"msecs"(0)); | |
//assert(d.timezone == new SimpleTimeZone(int.min)); | |
dp.parse("Tue, 20 May 2003 15:38:58 +0530", d); | |
assert(d.year == 2003); | |
assert(d.month == 5); | |
assert(d.day == 20); | |
assert(d.hour == 15); | |
assert(d.minute == 38); | |
assert(d.second == 58); | |
assert(d.fracSec == FracSec.from!"msecs"(0)); | |
//assert(d.timezone == new SimpleTimeZone(-530)); | |
debug(dateparse) printf("year = %d, month = %d, day = %d\n%02d:%02d:%02d.%03d\ntzcorrection = %d\n", | |
d.year, d.month, d.day, | |
d.hour, d.minute, d.second, d.fracSec, | |
d.timezone); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment