ParserFunctions: Add PHP implementation of strtotime [#661]

staging
gnosygnu 4 years ago
parent 3e9bc6d93a
commit bfce37f0ba

@ -151,5 +151,12 @@ public class DateAdp implements CompareAble, Gfo_invk {
this.under = new GregorianCalendar(year, month - Month_base0adj, day, hour, minute, second);
under.set(Calendar.MILLISECOND, frac);
}
public void SetTzOffset(int offset) {
java.util.Date date = under.getTime();
long msFromEpochGmt = date.getTime();
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(msFromEpochGmt - offset*1000);
under = cal;
}
public static final int Month_base0adj = 1;
}

@ -116,10 +116,24 @@ public class DateAdp_ implements Gfo_invk {
c.setTimeInMillis(v);
return new DateAdp(c);
}
public static final int SegIdx_year = 0, SegIdx_month = 1, SegIdx_day = 2, SegIdx_hour = 3, SegIdx_minute = 4, SegIdx_second = 5, SegIdx_frac = 6, SegIdx_dayOfWeek = 7, SegIdx_weekOfYear = 8, SegIdx_dayOfYear = 9, SegIdx__max = 10;
public static final int
SegIdx_year = 0, SegIdx_month = 1, SegIdx_day = 2, SegIdx_hour = 3, SegIdx_minute = 4, SegIdx_second = 5
, SegIdx_frac = 6, SegIdx_dayOfWeek = 7, SegIdx_weekOfYear = 8, SegIdx_dayOfYear = 9, SegIdx_tz = 10, SegIdx__max = 11;
public static String Xto_str_fmt_or(DateAdp v, String fmt, String or) {
return v == null ? or : v.XtoStr_fmt(fmt);
}
public static DateAdp FirstDayofYear(int year) {
return new DateAdp(year, 1, 1, 0, 0, 0, 0);
}
public static DateAdp DateByDayofYear(int year, int day) {
return new DateAdp(year, 1, day, 0, 0, 0, 0);
}
public static DateAdp DateByBits(int y, int m, int d, int h, int i, int s, int us, int tz_ofs, byte[] tz_abbr) {
DateAdp dte = new DateAdp(y, m, d, h, i, s, us/1000);
if (tz_ofs != 0)
dte.SetTzOffset(tz_ofs);
return dte;
}
public static final String
Fmt_iso8561_date_time = "yyyy-MM-dd HH:mm:ss"
, Fmt__yyyyMMdd = "yyyyMMdd";

@ -17,7 +17,7 @@ package gplx.xowa.addons.wikis.ctgs.bldrs; import gplx.*; import gplx.xowa.*; im
import org.junit.*; import gplx.core.tests.*;
public class Xob_catlink_mgr__tst {
private final Xob_catlink_mgr__fxt fxt = new Xob_catlink_mgr__fxt();
@Test public void Parse_timestamp() {
@Test public void Parse_timestamp() {// fix bad parsing b/c of "YYYY" instead of "yyyy"; ISSUE#:664; DATE:2020-02-05
fxt.Test__Parse_timestamp("2016-02-01 18:34:08", 1454351648); // fails if 1451241248
}
}

@ -0,0 +1,887 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
import gplx.core.btries.*;
public class Dbx_scan_support {
public static int TIMELIB_UNSET =-99999;
// timelib_public.h
public static final int TIMELIB_YEAR =1; //6; rearrange to same order as DateAdp_
public static final int TIMELIB_MONTH =2; //5;
public static final int TIMELIB_DAY =3; //4;
public static final int TIMELIB_HOUR =4; //3;
public static final int TIMELIB_MINUTE =5; //2;
public static final int TIMELIB_SECOND =6; //1;
public static final int TIMELIB_MICROSEC =7; //9;
public static final int TIMELIB_WEEKDAY =8; //7;
public static final int TIMELIB_SPECIAL =9; //8;
public static final int TIMELIB_SPECIAL_WEEKDAY =0x01;
public static final int TIMELIB_SPECIAL_DAY_OF_WEEK_IN_MONTH =0x02;
public static final int TIMELIB_SPECIAL_LAST_DAY_OF_WEEK_IN_MONTH =0x03;
public static final int TIMELIB_SPECIAL_FIRST_DAY_OF_MONTH =0x01;
public static final int TIMELIB_SPECIAL_LAST_DAY_OF_MONTH =0x02;
//#define SECS_PER_ERA 12622780800
public static final int SECS_PER_DAY =86400;
public static final int DAYS_PER_YEAR =365;
public static final int DAYS_PER_LYEAR =366;
/* 400*365 days + 97 leap days */
public static final int DAYS_PER_LYEAR_PERIOD =146097;
public static final int YEARS_PER_LYEAR_PERIOD =400;
public static final int TIMELIB_TZINFO_PHP =0x01;
public static final int TIMELIB_TZINFO_ZONEINFO =0x02;
// timelib.h
public static final int TIMELIB_WARN_MASK =0x1ff;
public static final int TIMELIB_ERR_MASK =0x2ff;
public static final int TIMELIB_WARN_DOUBLE_TZ =0x101;
public static final int TIMELIB_WARN_INVALID_TIME =0x102;
public static final int TIMELIB_WARN_INVALID_DATE =0x103;
public static final int TIMELIB_WARN_TRAILING_DATA =0x11a;
public static final int TIMELIB_ERR_DOUBLE_TZ =0x201;
public static final int TIMELIB_ERR_TZID_NOT_FOUND =0x202;
public static final int TIMELIB_ERR_DOUBLE_TIME =0x203;
public static final int TIMELIB_ERR_DOUBLE_DATE =0x204;
public static final int TIMELIB_ERR_UNEXPECTED_CHARACTER =0x205;
public static final int TIMELIB_ERR_EMPTY_STRING =0x206;
public static final int TIMELIB_ERR_UNEXPECTED_DATA =0x207;
public static final int TIMELIB_ERR_NO_TEXTUAL_DAY =0x208;
public static final int TIMELIB_ERR_NO_TWO_DIGIT_DAY =0x209;
public static final int TIMELIB_ERR_NO_THREE_DIGIT_DAY_OF_YEAR =0x20a;
public static final int TIMELIB_ERR_NO_TWO_DIGIT_MONTH =0x20b;
public static final int TIMELIB_ERR_NO_TEXTUAL_MONTH =0x20c;
public static final int TIMELIB_ERR_NO_TWO_DIGIT_YEAR =0x20d;
public static final int TIMELIB_ERR_NO_FOUR_DIGIT_YEAR =0x20e;
public static final int TIMELIB_ERR_NO_TWO_DIGIT_HOUR =0x20f;
public static final int TIMELIB_ERR_HOUR_LARGER_THAN_12 =0x210;
public static final int TIMELIB_ERR_MERIDIAN_BEFORE_HOUR =0x211;
public static final int TIMELIB_ERR_NO_MERIDIAN =0x212;
public static final int TIMELIB_ERR_NO_TWO_DIGIT_MINUTE =0x213;
public static final int TIMELIB_ERR_NO_TWO_DIGIT_SECOND =0x214;
public static final int TIMELIB_ERR_NO_SIX_DIGIT_MICROSECOND =0x215;
public static final int TIMELIB_ERR_NO_SEP_SYMBOL =0x216;
public static final int TIMELIB_ERR_EXPECTED_ESCAPE_CHAR =0x217;
public static final int TIMELIB_ERR_NO_ESCAPED_CHAR =0x218;
public static final int TIMELIB_ERR_WRONG_FORMAT_SEP =0x219;
public static final int TIMELIB_ERR_TRAILING_DATA =0x21a;
public static final int TIMELIB_ERR_DATA_MISSING =0x21b;
public static final int TIMELIB_ERR_NO_THREE_DIGIT_MILLISECOND =0x21c;
public static final int TIMELIB_ERR_NO_FOUR_DIGIT_YEAR_ISO =0x21d;
public static final int TIMELIB_ERR_NO_TWO_DIGIT_WEEK =0x21e;
public static final int TIMELIB_ERR_INVALID_WEEK =0x21f;
public static final int TIMELIB_ERR_NO_DAY_OF_WEEK =0x220;
public static final int TIMELIB_ERR_INVALID_DAY_OF_WEEK =0x221;
public static final int TIMELIB_ERR_INVALID_SPECIFIER =0x222;
public static final int TIMELIB_ERR_INVALID_TZ_OFFSET =0x223;
public static final int TIMELIB_ERR_FORMAT_LITERAL_MISMATCH =0x224;
public static final int TIMELIB_ERR_MIX_ISO_WITH_NATURAL =0x225;
public static final int TIMELIB_ZONETYPE_OFFSET =1;
public static final int TIMELIB_ZONETYPE_ABBR =2;
public static final int TIMELIB_ZONETYPE_ID =3;
//inside parse.re
public static final int TIMELIB_XMLRPC_SOAP =260;
public static final int TIMELIB_TIME12 =261;
public static final int TIMELIB_TIME24 =262;
public static final int TIMELIB_GNU_NOCOLON =263;
public static final int TIMELIB_GNU_NOCOLON_TZ =264;
public static final int TIMELIB_ISO_NOCOLON =265;
public static final int TIMELIB_AMERICAN =266;
public static final int TIMELIB_ISO_DATE =267;
public static final int TIMELIB_DATE_FULL =268;
public static final int TIMELIB_DATE_TEXT =269;
public static final int TIMELIB_DATE_NOCOLON =270;
public static final int TIMELIB_PG_YEARDAY =271;
public static final int TIMELIB_PG_TEXT =272;
public static final int TIMELIB_PG_REVERSE =273;
public static final int TIMELIB_CLF =274;
public static final int TIMELIB_DATE_NO_DAY =275;
public static final int TIMELIB_SHORTDATE_WITH_TIME =276;
public static final int TIMELIB_DATE_FULL_POINTED =277;
public static final int TIMELIB_TIME24_WITH_ZONE =278;
public static final int TIMELIB_ISO_WEEK =279;
public static final int TIMELIB_LF_DAY_OF_MONTH =280;
public static final int TIMELIB_WEEK_DAY_OF_MONTH =281;
public static final int TIMELIB_TIMEZONE =300;
public static final int TIMELIB_AGO =301;
public static final int TIMELIB_RELATIVE =310;
public static final int TIMELIB_ERROR =999;
private static Btrie_slim_mgr trie;
private static final Btrie_rv trv = new Btrie_rv();
public static void Init(Btrie_slim_mgr triex) {
trie = triex;
}
public static void add_error(Dbx_scanner s, int errcode, String str) {
throw Err_.new_unhandled(0); // break early
//s.errors.warning_count++;
//System.out.println("err: " + str);
}
public static void add_warning(Dbx_scanner s, int errcode, String str) {
throw Err_.new_unhandled(0); // break early
//s.errors.error_count++;
//System.out.println("warn: " + str);
}
public static boolean timelib_valid_time(int h, int i, int s)
{
if (h < 0 || h > 23 || i < 0 || i > 59 || s < 0 || s > 59) {
return false;
}
return true;
}
public static boolean timelib_valid_date(int y, int m, int d)
{
if (m < 1 || m > 12 || d < 1 /*|| d > timelib_days_in_month(y, m)*/) {
return false;
}
return true;
}
public static void TIMELIB_HAVE_TIME(Dbx_scanner s) {
if (s.time.have_time > 0) {
add_error(s, TIMELIB_ERR_DOUBLE_TIME, "Double time specification");
//timelib_string_free(str);
//throw return TIMELIB_ERROR;
} else {
s.time.have_time = 1;
s.time.h = 0;
s.time.i = 0;
s.time.s = 0;
s.time.us = 0;
}
}
public static void TIMELIB_UNHAVE_TIME(Dbx_scanner s) { s.time.have_time = 0; s.time.h = 0; s.time.i = 0; s.time.s = 0; s.time.us = 0; }
public static void TIMELIB_HAVE_DATE(Dbx_scanner s) {
if (s.time.have_date) {
add_error(s, TIMELIB_ERR_DOUBLE_DATE, "Double date specification");
//timelib_string_free(str);
//throw return TIMELIB_ERROR;
} else {
s.time.have_date = true;
}
}
public static void TIMELIB_UNHAVE_DATE(Dbx_scanner s) { s.time.have_date = false; s.time.d = 0; s.time.m = 0; s.time.y = 0; }
public static void TIMELIB_HAVE_RELATIVE(Dbx_scanner s) { s.time.have_relative = true; }
public static void TIMELIB_HAVE_WEEKDAY_RELATIVE(Dbx_scanner s) { s.time.have_relative = true; s.time.relative.have_weekday_relative = true; }
public static void TIMELIB_HAVE_SPECIAL_RELATIVE(Dbx_scanner s) { s.time.have_relative = true; s.time.relative.have_special_relative = true; }
public static void TIMELIB_HAVE_TZ(Dbx_scanner s) {
s.cur = s.cursor;
if (s.time.have_zone > 0) {
if (s.time.have_zone > 1)
add_error(s, TIMELIB_ERR_DOUBLE_TZ, "Double timezone specification");
else
add_warning(s, TIMELIB_WARN_DOUBLE_TZ, "Double timezone specification");
//timelib_string_free(str);
s.time.have_zone++;
//throw return TIMELIB_ERROR;
} else {
s.time.have_zone++;
}
}
public static void TIMELIB_PROCESS_YEAR(Dbx_scanner s) {
if ((s.time.y == TIMELIB_UNSET) || (s.length >= 4)) {
/* (s.time.y) = 0; */
} else if ((s.time.y) < 100) {
if ((s.time.y) < 70) {
(s.time.y) += 2000;
} else {
s.time.y += 1900;
}
}
}
public static void timelib_skip_day_suffix(Dbx_scanner s)
{
byte b = s.src[s.ptr];
if (b == ' ' || b == '\t') {
return;
}
byte b2 = s.src[s.ptr + 1];
if (b == 'n' && b2 == 'd' || b == 'r' && b2 == 'd' || b == 's' && b2 == 't' || b == 't' && b2 == 'h') {
s.ptr += 2;
}
}
public static void timelib_eat_spaces(Dbx_scanner s)
{
while (true) {
byte b = s.src[s.ptr];
if (b == ' ' || b == '\t') {
s.ptr++;
}
else
break;
}
}
//public static int timelib_get_nr(Dbx_scanner s, int size) { return 0; }
public static int timelib_get_nr_ex(Dbx_scanner s, int max_length) // sets s.length
{
int begin, end;
int len = 0;
while (true) {
byte b = s.src[s.ptr];
if (b < '0' || (b > '9')) {
if (b == '\0')
return TIMELIB_UNSET;
s.ptr++;
}
else
break;
}
begin = s.ptr;
while (true) {
byte b = s.src[s.ptr];
if (b >= '0' && (b <= '9') && len < max_length) {
++s.ptr;
++len;
}
else
break;
}
end = s.ptr;
s.length = end - begin;
int tmp_nr = TIMELIB_UNSET;
tmp_nr = Bry_.To_int_or(s.src, begin, end, Int_.Min_value);
return tmp_nr;
}
public static int timelib_get_month(Dbx_scanner s)
{
while (true) {
byte b = s.src[s.ptr];
if (b == ' ' || b == '\t' || b == '-' || b == '.' || b == '/')
++s.ptr;
else
break;
}
return timelib_lookup_month(s);
}
public static int timelib_lookup_month(Dbx_scanner s)
{
byte b = s.src[s.ptr];
Object o = trie.Match_at_w_b0(trv, b, s.src, s.ptr, s.src_len); // now match String against tkn
if (o == null) return TIMELIB_UNSET;
s.ptr = trv.Pos();
if (o instanceof Pxd_itm_month_name)
return ((Pxd_itm_month_name)o).Seg_val();
else
return TIMELIB_UNSET;
}
public static int timelib_meridian(Dbx_scanner s, int h)
{
int retval = 0;
byte b;
while (true) {
b = s.src[s.ptr];
if (b != 'A' && b != 'a' && b != 'P' && b != 'p') //!strchr("AaPp", **ptr))
++s.ptr;
else
break;
}
if (b == 'a' || b == 'A') {
if (h == 12) {
retval = -12;
}
} else if (h != 12) {
retval = 12;
}
b = s.src[++s.ptr];
if (b == '.') {
b = s.src[++s.ptr];
}
if (b == 'M' || b == 'm') {
b = s.src[++s.ptr];
}
if (b == '.') {
++s.ptr;
}
return retval;
}
public static timelib_relunit timelib_lookup_relunit(Dbx_scanner s)
//static const timelib_relunit* timelib_lookup_relunit(char **ptr)
{
byte b = s.src[s.ptr];
Object o = trie.Match_at_w_b0(trv, b, s.src, s.ptr, s.src_len); // now match String against tkn
if (o == null) return null;
s.ptr = trv.Pos();
if (o instanceof Pxd_itm_unit) {
timelib_relunit rv = new timelib_relunit();
Pxd_itm_unit itm = (Pxd_itm_unit)o;
rv.unit = itm.Seg_idx() + 1; // HACK to convert DateAdp_ constants to timelib constants
rv.multiplier = itm.Seg_multiple();
return rv;
}
else if (o instanceof Pxd_itm_dow_name) {
timelib_relunit rv = new timelib_relunit();
Pxd_itm_dow_name itm = (Pxd_itm_dow_name)o;
rv.unit = TIMELIB_WEEKDAY;
rv.multiplier = itm.Dow_idx();
return rv;
}
else if (o instanceof Pxd_itm_weekdays) {
timelib_relunit rv = new timelib_relunit();
rv.unit = TIMELIB_SPECIAL;
rv.multiplier = TIMELIB_SPECIAL_WEEKDAY;
return rv;
}
else
return null;
}
public static void timelib_set_relative(Dbx_scanner s, int amount, int behavior)
//static void timelib_set_relative(char **ptr, timelib_sll amount, int behavior, Scanner *s)
{
timelib_relunit relunit;
relunit = timelib_lookup_relunit(s);
if (relunit == null) {
return;
}
switch (relunit.unit) {
case TIMELIB_MICROSEC: s.time.relative.us += amount * relunit.multiplier; break;
case TIMELIB_SECOND: s.time.relative.s += amount * relunit.multiplier; break;
case TIMELIB_MINUTE: s.time.relative.i += amount * relunit.multiplier; break;
case TIMELIB_HOUR: s.time.relative.h += amount * relunit.multiplier; break;
case TIMELIB_DAY: s.time.relative.d += amount * relunit.multiplier; break;
case TIMELIB_MONTH: s.time.relative.m += amount * relunit.multiplier; break;
case TIMELIB_YEAR: s.time.relative.y += amount * relunit.multiplier; break;
case TIMELIB_WEEKDAY:
TIMELIB_HAVE_WEEKDAY_RELATIVE(s);
TIMELIB_UNHAVE_TIME(s);
s.time.relative.d += (amount > 0 ? amount - 1 : amount) * 7;
s.time.relative.weekday = relunit.multiplier;
s.time.relative.weekday_behavior = behavior;
break;
case TIMELIB_SPECIAL:
TIMELIB_HAVE_SPECIAL_RELATIVE(s);
TIMELIB_UNHAVE_TIME(s);
s.time.relative.special_type = relunit.multiplier;
s.time.relative.special_amount = amount;
}
}
public static int timelib_get_unsigned_nr(Dbx_scanner s, int max_length)
//static timelib_ull timelib_get_unsigned_nr(char **ptr, int max_length)
{
int dir = 1;
byte b;
while (true) {
b = s.src[s.ptr];
if ((b < '0' || b > '9') && b != '+' && b != '-') {
if (b == '\0')
return TIMELIB_UNSET;
s.ptr++;
}
else
break;
}
while (true) {
b = s.src[s.ptr];
if (b == '+' || b == '-') {
if (b == '-')
dir *= -1;
++s.ptr;
}
else
break;
}
return dir * timelib_get_nr_ex(s, max_length);
}
public static int timelib_get_relative_text(Dbx_scanner s) // sets s.behavior
//static timelib_sll timelib_get_relative_text(char **ptr, int *behavior)
{
while (true) {
byte b = s.src[s.ptr];
if (b == ' ' || b == '\t' || b == '-' || b == '/')
++s.ptr;
else
break;
}
return timelib_lookup_relative_text(s);
}
public static int timelib_lookup_relative_text(Dbx_scanner s) // sets s.behavior
//static timelib_sll timelib_lookup_relative_text(char **ptr, int *behavior)
{
byte b = s.src[s.ptr];
Object o = trie.Match_at_w_b0(trv, b, s.src, s.ptr, s.src_len); // now match String against tkn
if (o == null) return TIMELIB_UNSET;
s.ptr = trv.Pos();
s.behavior = 0;
if (o instanceof Pxd_itm_unit) //"second" is a unit!!!!
return 2;
if (o instanceof Pxd_itm_ordinal)
return ((Pxd_itm_ordinal)o).Ord_val();
if (o instanceof Pxd_itm_unit_relative) {
// need to handle 'this, next, previous, last'
// 'this' set behavior to 1
// what does NULL do???
int adj = ((Pxd_itm_unit_relative)o).Adj();
if (adj == 0) // 'this'
s.behavior = 1;
return adj;
}
else
return TIMELIB_UNSET;
}
public static int timelib_daynr_from_weeknr(int y, int w, int d)
{
/* Figure out the dayofweek for y-1-1 */
DateAdp yearstart = DateAdp_.FirstDayofYear(y); // should timezone be involved?
int dow = yearstart.DayOfWeek();
//dow = timelib_day_of_week(iy, 1, 1);
/* then use that to figure out the offset for day 1 of week 1 */
int day = 0 - (dow > 4 ? dow - 7 : dow);
/* Add weeks and days */
return day + ((w - 1) * 7) + d;
}
public static int timelib_get_frac_nr(Dbx_scanner s, int max_length)
//static timelib_sll timelib_get_frac_nr(char **ptr, int max_length)
{
int begin, end;
double tmp_nr = TIMELIB_UNSET;
int len = 0;
while (true) {
byte b = s.src[s.ptr];
if ((b != '.') && (b != ':') && ((b < '0') || (b > '9'))) {
if (b == '\0')
return TIMELIB_UNSET;
s.ptr++;
}
else
break;
}
begin = s.ptr;
while (true) {
byte b = s.src[s.ptr];
if (((b == '.') || (b == ':') || ((b >= '0') && (b <= '9'))) && len < max_length) {
++s.ptr;
++len;
}
else
break;
}
end = s.ptr;
s.length = end - begin;
tmp_nr = Bry_.To_double_or(s.src, begin, end, Int_.Min_value) * Math.pow(10, 7 - (end - begin));
return (int)tmp_nr;
}
public static int timelib_parse_zone(Dbx_scanner s) // sets tz_not_found
//timelib_parse_zone((char **) &ptr, &s->time->dst, s->time, &tz_not_found, s->tzdb, tz_get_wrapper);
//timelib_long timelib_parse_zone(char **ptr, int *dst, timelib_time *t, int *tz_not_found, const timelib_tzdb *tzdb, timelib_tz_get_wrapper tz_wrapper)
{
//timelib_tzinfo *res;
int retval = 0;
timelib_time t = s.time;
s.tz_not_found = 0;
byte b;
while (true) {
b = s.src[s.ptr];
if (b == ' ' || b == '\t' || b == '(') {
s.ptr++;
}
else
break;
}
s.tz_not_found = 1;
byte[] lsrc = s.src;
int pos = s.ptr;
if (lsrc[pos + 0] == 'G' && lsrc[pos + 1] == 'M' && lsrc[pos + 2] == 'T' && (lsrc[pos + 3] == '+' || lsrc[pos + 3] == '-')) {
s.ptr += 3;
}
b = s.src[s.ptr];
if (b == '+') {
++s.ptr;
t.is_localtime = true;
t.zone_type = TIMELIB_ZONETYPE_OFFSET;
s.tz_not_found = 0;
t.dst = 0;
retval = timelib_parse_tz_cor(s);
} else if (b == '-') {
++s.ptr;
t.is_localtime = true;
t.zone_type = TIMELIB_ZONETYPE_OFFSET;
s.tz_not_found = 0;
t.dst = 0;
retval = -1 * timelib_parse_tz_cor(s);
} else {
int found = 0;
int offset = 0;
//char *tz_abbr;
t.is_localtime = true;
/* First, we lookup by abbreviation only */
b = s.src[s.ptr];
Object o = trie.Match_at_w_b0(trv, b, s.src, s.ptr, s.src_len); // now match String against tkn
if (o != null && o instanceof Pxd_itm_tz_abbr) {
s.ptr = trv.Pos();
t.zone_type = TIMELIB_ZONETYPE_ABBR;
retval = ((Pxd_itm_tz_abbr)o).Tz_offset();
t.tz_abbr = ((Pxd_itm_tz_abbr)o).Tz_abbr();
s.tz_not_found = 0;
}
// offset = timelib_lookup_abbr(ptr, dst, &tz_abbr, &found);
// if (found) {
// t.zone_type = TIMELIB_ZONETYPE_ABBR;
// timelib_time_tz_abbr_update(t, tz_abbr);
// }
//
// /* Otherwise, we look if we have a TimeZone identifier */
// if (!found || strcmp("UTC", tz_abbr) == 0) {
// int dummy_error_code;
//
// if ((res = tz_wrapper(tz_abbr, tzdb, &dummy_error_code)) != NULL) {
// t.tz_info = res;
// t.zone_type = TIMELIB_ZONETYPE_ID;
// found++;
// }
// }
// timelib_free(tz_abbr);
// s.tz_not_found = (found == 0);
// retval = offset;
}
while (true) {
b = s.src[s.ptr];
if (b == ')') {
s.ptr++;
}
else
break;
}
return retval;
}
public static int TIMELIB_OVERRIDE_TIME = 1;
public static void timelib_fill_holes(timelib_time parsed, timelib_time now, int options)
{
if ((options & TIMELIB_OVERRIDE_TIME) != TIMELIB_OVERRIDE_TIME && parsed.have_date && parsed.have_time == 0) {
parsed.h = 0;
parsed.i = 0;
parsed.s = 0;
parsed.us = 0;
}
if (
parsed.y != TIMELIB_UNSET || parsed.m != TIMELIB_UNSET || parsed.d != TIMELIB_UNSET ||
parsed.h != TIMELIB_UNSET || parsed.i != TIMELIB_UNSET || parsed.s != TIMELIB_UNSET
) {
if (parsed.us == TIMELIB_UNSET) parsed.us = 0;
} else {
if (parsed.us == TIMELIB_UNSET) parsed.us = now.us != TIMELIB_UNSET ? now.us : 0;
}
if (parsed.y == TIMELIB_UNSET) parsed.y = now.y != TIMELIB_UNSET ? now.y : 0;
if (parsed.m == TIMELIB_UNSET) parsed.m = now.m != TIMELIB_UNSET ? now.m : 0;
if (parsed.d == TIMELIB_UNSET) parsed.d = now.d != TIMELIB_UNSET ? now.d : 0;
if (parsed.h == TIMELIB_UNSET) parsed.h = now.h != TIMELIB_UNSET ? now.h : 0;
if (parsed.i == TIMELIB_UNSET) parsed.i = now.i != TIMELIB_UNSET ? now.i : 0;
if (parsed.s == TIMELIB_UNSET) parsed.s = now.s != TIMELIB_UNSET ? now.s : 0;
if (parsed.z == TIMELIB_UNSET) parsed.z = now.z != TIMELIB_UNSET ? now.z : 0;
if (parsed.dst == TIMELIB_UNSET) parsed.dst = now.dst != TIMELIB_UNSET ? now.dst : 0;
if (parsed.tz_abbr != null) {
//parsed.tz_abbr = now.tz_abbr != null ? timelib_strdup(now.tz_abbr) : null;
}
//if (parsed.tz_info != null) {
// parsed.tz_info = now.tz_info ? (!(options & TIMELIB_NO_CLONE) ? timelib_tzinfo_clone(now.tz_info) : now.tz_info) : NULL;
//}
if (parsed.zone_type == 0 && now.zone_type != 0) {
parsed.zone_type = now.zone_type;
/* parsed.tz_abbr = now.tz_abbr ? timelib_strdup(now.tz_abbr) : NULL;
parsed.tz_info = now.tz_info ? timelib_tzinfo_clone(now.tz_info) : NULL;
*/ parsed.is_localtime = true;
}
/* timelib_dump_date(parsed, 2);
timelib_dump_date(now, 2);
*/
}
private static timelib_time timelib_now() {
DateAdp now = Datetime_now.Get();
timelib_time nowtime = new timelib_time();
nowtime.y = now.Year();
nowtime.m = now.Month();
nowtime.d = now.Day();
nowtime.h = now.Hour();
nowtime.i = now.Minute();
nowtime.s = now.Second();
//us = 0; //Dbx_scan_support.TIMELIB_UNSET;
//z = 0; //Dbx_scan_support.TIMELIB_UNSET;
//dst = 0; //Dbx_scan_support.TIMELIB_UNSET;
return nowtime;
}
private static int timelib_day_of_week(int y, int m, int d) {
DateAdp dte = DateAdp_.DateByBits(y, m, d, 0, 0, 0, 0, 0, null);
return dte.DayOfWeek();
}
private static void do_adjust_for_weekday(timelib_time time)
{
int current_dow, difference;
current_dow = timelib_day_of_week(time.y, time.m, time.d);
if (time.relative.weekday_behavior == 2)
{
/* To make "this week" work, where the current DOW is a "sunday" */
if (current_dow == 0 && time.relative.weekday != 0) {
time.relative.weekday -= 7;
}
/* To make "sunday this week" work, where the current DOW is not a
* "sunday" */
if (time.relative.weekday == 0 && current_dow != 0) {
time.relative.weekday = 7;
}
time.d -= current_dow;
time.d += time.relative.weekday;
return;
}
difference = time.relative.weekday - current_dow;
if ((time.relative.d < 0 && difference < 0) || (time.relative.d >= 0 && difference <= -time.relative.weekday_behavior)) {
difference += 7;
}
if (time.relative.weekday >= 0) {
time.d += difference;
} else {
time.d -= (7 - (Math.abs(time.relative.weekday) - current_dow));
}
time.relative.have_weekday_relative = false;
}
private static void do_adjust_relative(timelib_time time)
{
if (time.relative.have_weekday_relative) {
do_adjust_for_weekday(time);
}
//timelib_do_normalize(time);
if (time.have_relative) {
time.us += time.relative.us;
time.s += time.relative.s;
time.i += time.relative.i;
time.h += time.relative.h;
time.d += time.relative.d;
time.m += time.relative.m;
time.y += time.relative.y;
}
switch (time.relative.first_last_day_of) {
case TIMELIB_SPECIAL_FIRST_DAY_OF_MONTH: /* first */
time.d = 1;
break;
case TIMELIB_SPECIAL_LAST_DAY_OF_MONTH: /* last */
time.d = 0;
time.m++;
break;
}
//?? timelib_do_normalize(time);
}
private static void do_adjust_special_weekday(timelib_time time)
{
int count, dow, rem;
count = time.relative.special_amount;
dow = timelib_day_of_week(time.y, time.m, time.d);
/* Add increments of 5 weekdays as a week, leaving the DOW unchanged. */
time.d += (count / 5) * 7;
/* Deal with the remainder. */
rem = (count % 5);
if (count > 0) {
if (rem == 0) {
/* Head back to Friday if we stop on the weekend. */
if (dow == 0) {
time.d -= 2;
} else if (dow == 6) {
time.d -= 1;
}
} else if (dow == 6) {
/* We ended up on Saturday, but there's still work to do, so move
* to Sunday and continue from there. */
time.d += 1;
} else if (dow + rem > 5) {
/* We're on a weekday, but we're going past Friday, so skip right
* over the weekend. */
time.d += 2;
}
} else {
/* Completely mirror the forward direction. This also covers the 0
* case, since if we start on the weekend, we want to move forward as
* if we stopped there while going backwards. */
if (rem == 0) {
if (dow == 6) {
time.d += 2;
} else if (dow == 0) {
time.d += 1;
}
} else if (dow == 0) {
time.d -= 1;
} else if (dow + rem < 1) {
time.d -= 2;
}
}
time.d += rem;
}
private static void do_adjust_special(timelib_time time)
{
if (time.relative.have_special_relative) {
switch (time.relative.special_type) {
case TIMELIB_SPECIAL_WEEKDAY:
do_adjust_special_weekday(time);
break;
}
}
// timelib_do_normalize(time);
// memset(&(time.relative.special), 0, sizeof(time.relative.special));
}
private static void do_adjust_special_early(timelib_time time)
{
if (time.relative.have_special_relative) {
switch (time.relative.special_type) {
case TIMELIB_SPECIAL_DAY_OF_WEEK_IN_MONTH:
time.d = 1;
time.m += time.relative.m;
time.relative.m = 0;
break;
case TIMELIB_SPECIAL_LAST_DAY_OF_WEEK_IN_MONTH:
time.d = 1;
time.m += time.relative.m + 1;
time.relative.m = 0;
break;
}
}
switch (time.relative.first_last_day_of) {
case TIMELIB_SPECIAL_FIRST_DAY_OF_MONTH: /* first */
time.d = 1;
break;
case TIMELIB_SPECIAL_LAST_DAY_OF_MONTH: /* last */
time.d = 0;
time.m++;
break;
}
// timelib_do_normalize(time);
}
private static int timelib_parse_tz_cor(Dbx_scanner s)
{
int begin, end;
int tmp = 0;
begin = s.ptr;
while (true) {
byte b = s.src[s.ptr];
if ((b >= '0' && b <= '9') || b == ':') {
++s.ptr;
}
else
break;
}
end = s.ptr;
switch (end - begin) {
case 1: /* H */
case 2: /* HH */
tmp = Bry_.To_int_or(s.src, begin, end, Int_.Min_value);
return tmp * 3600;
case 3: /* H:M */
case 4: /* H:MM, HH:M, HHMM */
if (s.src[begin + 1] == ':') {
tmp = Bry_.To_int_or(s.src, begin, begin+1, Int_.Min_value) * 3600 +
Bry_.To_int_or(s.src, begin+2, end, Int_.Min_value) * 60;
return tmp;
} else if (s.src[begin + 2] == ':') {
tmp = Bry_.To_int_or(s.src, begin, begin+2, Int_.Min_value) * 3600 +
Bry_.To_int_or(s.src, begin+3, end, Int_.Min_value) * 60;
return tmp;
} else {
tmp = Bry_.To_int_or(s.src, begin, end, Int_.Min_value);
return tmp / 100 * 3600 + (tmp % 100) * 60;
}
case 5: /* HH:MM */
tmp = Bry_.To_int_or(s.src, begin, begin+2, Int_.Min_value) * 3600 +
Bry_.To_int_or(s.src, begin+3, end, Int_.Min_value) * 60;
return tmp;
}
return 0;
}
private static void timelib_update_ts(timelib_time time)
{
do_adjust_special_early(time);
do_adjust_relative(time);
do_adjust_special(time);
}
public static DateAdp Parse(byte[] src) {
timelib_time parsed = Dbx_strtotime.timelib_strtotime(src);
// check for errors
timelib_time now = timelib_now();
timelib_fill_holes(parsed, now, 0);
timelib_update_ts(parsed);
DateAdp dte = DateAdp_.DateByBits(parsed.y, parsed.m, parsed.d, parsed.h, parsed.i, parsed.s, parsed.us, parsed.z, parsed.tz_abbr);
return dte;
}
}

@ -0,0 +1,139 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
class Dbx_scanner {
//int fd;
//uchar *lim, *str, *ptr, *cur, *tok, *pos;
public int lim;
public byte[] src;
public int src_len;
public int ptr;
public int cur;
public int tok;
public int pos;
public int line, len;
public int state;
public int cursor;
public int yyaccept;
public int yych;
public timelib_error_container errors;
public timelib_time time;
//const timelib_tzdb *tzdb;
int length;
int behavior;
public int tz_not_found;
public Dbx_scanner(byte[] srcx, int maxfill) {
errors = new timelib_error_container();
time = new timelib_time();
int slen = srcx.length;
lim = slen + maxfill;
src = new byte[lim];
int i;
for (i = 0; i < lim; i++)
src[i] = 0;
for (i = 0; i < slen; i++)
src[i] = srcx[i];
//src = Bry_.Add(srcx, Byte_ascii.Null);
src_len = slen;
ptr = 0;
cur = 0;
tok = 0;
pos = 0;
line = 0;
}
}
class timelib_error_container {
public byte[] error_messages;
public byte[] warning_messages;
public int error_count;
public int warning_count;
public timelib_error_container() {
warning_count = 0;
warning_messages = null;
error_count = 0;
error_messages = null;
}
}
class timelib_time {
public int y, m, d; /* Year, Month, Day */
public int h, i, s; /* Hour, mInute, Second */
public int us; /* Microseconds */
public int z; /* UTC offset in seconds */
public byte[] tz_abbr; /* Timezone abbreviation (display only) */
//timelib_tzinfo *tz_info; /* Timezone structure */
public int dst; /* Flag if we were parsing a DST zone */
public timelib_rel_time relative;
public int sse; /* Seconds since epoch */
public boolean have_date, have_relative, have_weeknr_day;
public int have_time;
public int have_zone;
public boolean sse_uptodate; /* !0 if the sse member is up to date with the date/time members */
public boolean tim_uptodate; /* !0 if the date/time members are up to date with the sse member */
public boolean is_localtime; /* 1 if the current struct represents localtime, 0 if it is in GMT */
public int zone_type; /* 1 time offset,
* 3 TimeZone identifier,
* 2 TimeZone abbreviation */
public timelib_time() {
//in.time = timelib_time_ctor();
y = Dbx_scan_support.TIMELIB_UNSET;
d = Dbx_scan_support.TIMELIB_UNSET;
m = Dbx_scan_support.TIMELIB_UNSET;
h = Dbx_scan_support.TIMELIB_UNSET;
i = Dbx_scan_support.TIMELIB_UNSET;
s = Dbx_scan_support.TIMELIB_UNSET;
us = Dbx_scan_support.TIMELIB_UNSET;
z = Dbx_scan_support.TIMELIB_UNSET;
dst = Dbx_scan_support.TIMELIB_UNSET;
//in.tzdb = tzdb;
is_localtime = false;
zone_type = 0;
relative = new timelib_rel_time();
relative.days = Dbx_scan_support.TIMELIB_UNSET;
}
}
class timelib_rel_time {
public int y, m, d; /* Years, Months and Days */
public int h, i, s; /* Hours, mInutes and Seconds */
public int us; /* Microseconds */
public int weekday; /* Stores the day in 'next monday' */
public int weekday_behavior; /* 0: the current day should *not* be counted when advancing forwards; 1: the current day *should* be counted */
public int first_last_day_of;
public int invert; /* Whether the difference should be inverted */
public int days; /* Contains the number of *days*, instead of Y-M-D differences */
public int special_type;
public int special_amount;
public boolean have_weekday_relative, have_special_relative;
}
class timelib_relunit {
public byte[] name;
public int unit;
public int multiplier;
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,49 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.xtns.pfuncs.times; import org.junit.After;
import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
import gplx.core.tests.*;
import gplx.core.btries.*;
import org.junit.Before;
import org.junit.Test;
public class Dbx_strtotime_tst {
private final Dbx_strtotime_fxt fxt = new Dbx_strtotime_fxt();
@Before public void setup() {
Datetime_now.Manual_(DateAdp_.new_(2012, 1, 2, 3, 4, 5, 6));
}
@After public void teardown() {
Datetime_now.Manual_n_();
}
@Test public void Basic() {
// "{{#time:r|n.d.}}", "Sat, 08 Feb 2020 22:57:12 +0000");
// fxt.Test__date("n.d.", "Sat, 08 Feb 2020 22:57:12 +0000");
// fxt.Test__date("30.6.2011-06-30", "Sat, 08 Feb 2020 22:57:12 +0000");
// fxt.Test__date("7 May 2013", "2013-05-07 00:00:00");
}
}
class Dbx_strtotime_fxt {
public Dbx_strtotime_fxt() {
Btrie_slim_mgr trie = Pxd_parser_.Trie();
Dbx_scan_support.Init(trie);
}
public void Test__date(String raw, String expd) {
DateAdp date = Dbx_scan_support.Parse(Bry_.new_u8(raw));
Gftest.Eq__str(expd, date.XtoStr_fmt_iso_8561());
}
}

@ -41,6 +41,10 @@ class Pxd_itm_ {
, Tid_unixtime = 12 // @123
, Tid_iso8601_t = 13 // T
, Tid_meridian = 14 // PM
, Tid_tz_abbr = 15 // timezone abbreviation
, Tid_weekofyear = 16
, Tid_ord_name = 17
, Tid_weekdays = 18
, Tid_dash = Byte_ascii.Dash
, Tid_dot = Byte_ascii.Dot
, Tid_slash = Byte_ascii.Slash

@ -27,6 +27,7 @@ class Pxd_itm_dow_name extends Pxd_itm_base implements Pxd_itm_prototype {
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_dow_name;}
@Override public int Eval_idx() {return 20;}
public Pxd_itm MakeNew(int ary_idx) {return new Pxd_itm_dow_name(ary_idx, dow_name, dow_idx);}
public int Dow_idx() {return dow_idx;}
public void Relative_adj_(int v) { // handled by relative_word; EX: "next tuesday"
this.relative_adj = v;
}

@ -26,6 +26,7 @@ class Pxd_itm_month_name extends Pxd_itm_base implements Pxd_itm_prototype {
}
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_month_name;}
@Override public int Eval_idx() {return 20;}
public int Seg_val() {return seg_val;}
public Pxd_itm MakeNew(int ary_idx) {
Pxd_itm_month_name rv = new Pxd_itm_month_name(ary_idx, name, this.Seg_idx(), seg_val);
return rv;
@ -165,6 +166,7 @@ class Pxd_itm_unit extends Pxd_itm_base implements Pxd_itm_prototype {
}
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_unit;}
@Override public int Eval_idx() {return 10;}
public int Seg_multiple() {return seg_multiple;}
public byte[] Name() {return name;} private final byte[] name;
public Pxd_itm MakeNew(int ary_idx) {
return new Pxd_itm_unit(ary_idx, name, this.Seg_idx(), seg_val);

@ -0,0 +1,47 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
class Pxd_itm_ordinal extends Pxd_itm_base implements Pxd_itm_prototype {
private final int ord_idx;
public int Ord_val() { return ord_idx; }
private final byte[] ord_name;
public Pxd_itm_ordinal(int ary_idx, byte[] ord_name, int ord_idx) {
this.ord_name = ord_name;
this.ord_idx = ord_idx;
this.Ctor(ary_idx);
}
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_ord_name;}
@Override public int Eval_idx() {return 99;}
public Pxd_itm MakeNew(int ary_idx) {return new Pxd_itm_ordinal(ary_idx, ord_name, ord_idx);}
@Override public boolean Eval(Pxd_parser state) {return true;}
@Override public boolean Time_ini(Pxd_date_bldr bldr) {
return true;
}
}
class Pxd_itm_weekdays extends Pxd_itm_base implements Pxd_itm_prototype {
private final byte[] ord_name;
public Pxd_itm_weekdays(int ary_idx, byte[] ord_name) {
this.ord_name = ord_name;
this.Ctor(ary_idx);
}
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_weekdays;}
@Override public int Eval_idx() {return 99;}
public Pxd_itm MakeNew(int ary_idx) {return new Pxd_itm_weekdays(ary_idx, ord_name);}
@Override public boolean Eval(Pxd_parser state) {return true;}
@Override public boolean Time_ini(Pxd_date_bldr bldr) {
return true;
}
}

@ -0,0 +1,45 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
class Pxd_itm_tz_abbr extends Pxd_itm_base implements Pxd_itm_prototype {
private final int tz_idx;
private final byte[] tz_abbr;
private final int tz_offset;
public int Tz_offset() { return tz_offset; }
public byte[] Tz_abbr() { return tz_abbr; }
public Pxd_itm_tz_abbr(int ary_idx, byte[] tz_abbr, int tz_idx, int offset) {
this.tz_abbr = tz_abbr;
this.tz_idx = tz_idx;
this.tz_offset = offset;
this.Ctor(ary_idx);
this.Seg_idx_(DateAdp_.SegIdx_tz);
}
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_tz_abbr;}
@Override public int Eval_idx() {return 90;}
public Pxd_itm MakeNew(int ary_idx) {return new Pxd_itm_tz_abbr(ary_idx, tz_abbr, tz_idx, tz_offset);}
@Override public boolean Eval(Pxd_parser state) {
// just to check how often used
if (tz_offset != 0)
return false;
return true;
}
@Override public boolean Time_ini(Pxd_date_bldr bldr) {
DateAdp cur = bldr.To_date();
cur = cur.Add_second(-tz_offset);
bldr.By_date(cur);
return true;
}
}

@ -24,6 +24,7 @@ class Pxd_itm_unit_relative extends Pxd_itm_base implements Pxd_itm_prototype {
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_unit_relative;}
@Override public int Eval_idx() {return 5;}
public Pxd_itm MakeNew(int ary_idx) {return new Pxd_itm_unit_relative(adj, ary_idx);}
public int Adj() {return adj;}
@Override public boolean Eval(Pxd_parser state) {
// find next token: EX: year, month, Sunday, Monday, etc.
Pxd_itm itm = Pxd_itm_.Find_fwd__non_ws(state.Tkns(), this.Ary_idx() + 1);

Loading…
Cancel
Save