1
0
mirror of https://github.com/gnosygnu/xowa.git synced 2026-03-02 03:49:30 +00:00
This commit is contained in:
gnosygnu
2015-07-12 21:10:02 -04:00
commit 794b5a232f
3099 changed files with 238212 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
public interface Pft_fmt_itm {
int TypeId();
void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr);
}

View File

@@ -0,0 +1,189 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
import gplx.core.btries.*;
public class Pft_fmt_itm_ {
public static final int
Tid_seg_int = 1
, Tid_hour_base12 = 2
, Tid_dow_base0 = 3
, Tid_seg_str = 4
, Tid_year_isLeap = 5
, Tid_timestamp_unix = 6
, Tid_raw_ary = 7
, Tid_raw_byt = 8
, Tid_dayOfYear = 9
, Tid_daysInMonth = 10
, Tid_AmPm = 11
, Tid_roman = 12
, Tid_iso_fmt = 13
, Tid_rfc_5322 = 14
, Tid_raw = 15
, Tid_timezone_offset = 16
, Tid_thai = 17
, Tid_minguo = 18
, Tid_hebrew_year_num = 21
, Tid_hebrew_month_num = 20
, Tid_hebrew_day_num = 19
, Tid_hebrew_month_days_count = 22
, Tid_hebrew_month_name_full = 23
, Tid_hebrew_month_name_gen = 24
, Tid_hebrew_numeral = 25
;
public static final Pft_fmt_itm
Year_len4 = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_year , 4, Bool_.Y)
, Year_len2 = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_year , 2, Bool_.Y)
, Month_int_len2 = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_month , 2, Bool_.Y)
, Month_int = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_month , 2, Bool_.N)
, Day_int_len2 = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_day , 2, Bool_.Y)
, Day_int = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_day , 2, Bool_.N)
, Hour_base24_len2 = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_hour , 2, Bool_.Y)
, Hour_base24 = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_hour , 2, Bool_.N)
, Hour_base12_len2 = new Pft_fmt_itm_hour_base12(Bool_.Y)
, Hour_base12 = new Pft_fmt_itm_hour_base12(Bool_.N)
, Minute_int_len2 = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_minute , 2, Bool_.Y)
, Second_int_len2 = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_second , 2, Bool_.Y)
, Dow_base1_int = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_dayOfWeek , 1, Bool_.Y)
, Dow_base0_int = new Pft_fmt_itm_dow_base0()
, WeekOfYear_int = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_weekOfYear , 2, Bool_.N)
, WeekOfYear_int_len2 = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_weekOfYear , 2, Bool_.Y)
, Month_abrv = new Pft_fmt_itm_seg_str(DateAdp_.SegIdx_month, Xol_msg_itm_.Id_dte_month_abrv_jan - Int_.Base1) // Jan
, Month_name = new Pft_fmt_itm_seg_str(DateAdp_.SegIdx_month, Xol_msg_itm_.Id_dte_month_name_january - Int_.Base1) // January
, Month_gen = new Pft_fmt_itm_seg_str(DateAdp_.SegIdx_month, Xol_msg_itm_.Id_dte_month_gen_january - Int_.Base1) // January
, Dow_abrv = new Pft_fmt_itm_seg_str(DateAdp_.SegIdx_dayOfWeek, Xol_msg_itm_.Id_dte_dow_abrv_sun) // Sun
, Dow_name = new Pft_fmt_itm_seg_str(DateAdp_.SegIdx_dayOfWeek, Xol_msg_itm_.Id_dte_dow_name_sunday) // Sunday
, Year_isLeap = new Pft_fmt_itm_year_isLeap()
, Timestamp_unix = new Pft_fmt_itm_timestamp_unix()
, Byte_space = new Pft_fmt_itm_raw_byt(Byte_ascii.Space)
, Byte_comma = new Pft_fmt_itm_raw_byt(Byte_ascii.Comma)
, Byte_dash = new Pft_fmt_itm_raw_byt(Byte_ascii.Dash)
, DayOfYear_int = new Pft_fmt_itm_dayOfYear()
, DaysInMonth_int = new Pft_fmt_itm_daysInMonth()
, AmPm_lower = new Pft_fmt_itm_am_pm(true)
, AmPm_upper = new Pft_fmt_itm_am_pm(false)
, Roman = new Pft_fmt_itm_roman()
, Thai = new Pft_fmt_itm_thai()
, Minguo = new Pft_fmt_itm_minguo()
, Hebrew_year_num = new Pft_fmt_itm_hebrew_year_num()
, Hebrew_month_num = new Pft_fmt_itm_hebrew_month_num()
, Hebrew_day_num = new Pft_fmt_itm_hebrew_day_num()
, Hebrew_month_days_count = new Pft_fmt_itm_hebrew_month_days_count()
, Hebrew_month_name_full = new Pft_fmt_itm_hebrew_month_name_full()
, Hebrew_month_name_gen = new Pft_fmt_itm_hebrew_month_name_gen()
, Hebrew_numeral = new Pft_fmt_itm_hebrew_numeral()
, Raw = new Pft_fmt_itm_raw()
, Iso_fmt = new Pft_fmt_itm_iso_fmt()
, Rfc_5322 = new Pft_fmt_itm_rfc_5322()
, Timezone_offset = new Pft_fmt_itm_timezone_offset()
;
public static final Btrie_fast_mgr Regy = Btrie_fast_mgr.cs_()
.Add(Byte_ascii.Ltr_Y , Pft_fmt_itm_.Year_len4) // 2012
.Add(Byte_ascii.Ltr_y , Pft_fmt_itm_.Year_len2) // 12
.Add(Byte_ascii.Ltr_L , Pft_fmt_itm_.Year_isLeap) // 1,0
.Add(Byte_ascii.Ltr_o , Pft_fmt_itm_.Year_len4) // 2012: ISO-8601; don't know why it's different vs Ltr_Y
.Add(Byte_ascii.Ltr_n , Pft_fmt_itm_.Month_int) // 1
.Add(Byte_ascii.Ltr_m , Pft_fmt_itm_.Month_int_len2) // 01
.Add(Byte_ascii.Ltr_M , Pft_fmt_itm_.Month_abrv) // Jan
.Add(Byte_ascii.Ltr_F , Pft_fmt_itm_.Month_name) // January
.Add("xg" , Pft_fmt_itm_.Month_gen) // January
.Add(Byte_ascii.Ltr_W , Pft_fmt_itm_.WeekOfYear_int_len2) // 01
.Add(Byte_ascii.Ltr_j , Pft_fmt_itm_.Day_int) // 1
.Add(Byte_ascii.Ltr_d , Pft_fmt_itm_.Day_int_len2) // 01
.Add(Byte_ascii.Ltr_z , Pft_fmt_itm_.DayOfYear_int) // 0
.Add(Byte_ascii.Ltr_D , Pft_fmt_itm_.Dow_abrv) // Sun
.Add(Byte_ascii.Ltr_l , Pft_fmt_itm_.Dow_name) // Sunday
.Add(Byte_ascii.Ltr_N , Pft_fmt_itm_.Dow_base0_int) // 1; Sunday=7
.Add(Byte_ascii.Ltr_w , Pft_fmt_itm_.Dow_base1_int) // 1; Sunday=0
.Add(Byte_ascii.Ltr_a , Pft_fmt_itm_.AmPm_lower) // am/pm
.Add(Byte_ascii.Ltr_A , Pft_fmt_itm_.AmPm_upper) // AM/PM
.Add(Byte_ascii.Ltr_g , Pft_fmt_itm_.Hour_base12) // 1; Base12
.Add(Byte_ascii.Ltr_h , Pft_fmt_itm_.Hour_base12_len2) // 01; Base12; pad2
.Add(Byte_ascii.Ltr_G , Pft_fmt_itm_.Hour_base24) // 13; Base24;
.Add(Byte_ascii.Ltr_H , Pft_fmt_itm_.Hour_base24_len2) // 13; Base24; pad2
.Add(Byte_ascii.Ltr_i , Pft_fmt_itm_.Minute_int_len2) // 04
.Add(Byte_ascii.Ltr_s , Pft_fmt_itm_.Second_int_len2) // 05
.Add(Byte_ascii.Ltr_t , Pft_fmt_itm_.DaysInMonth_int) // 31
.Add(Byte_ascii.Ltr_U , Pft_fmt_itm_.Timestamp_unix) // 1343865600
.Add(Byte_ascii.Ltr_Z , Pft_fmt_itm_.Timezone_offset) // timezone offset in seconds
.Add(Byte_ascii.Ltr_c , Pft_fmt_itm_.Iso_fmt) // 2012-01-02T03:04:05+00:00
.Add(Byte_ascii.Ltr_r , Pft_fmt_itm_.Rfc_5322) // Mon 02 Jan 2012 08:04:05 +0000
.Add("xr" , Pft_fmt_itm_.Roman) // MCXI
.Add("xkY" , Pft_fmt_itm_.Thai) // Year += 543
.Add("xoY" , Pft_fmt_itm_.Minguo) // Year -= 1911
.Add("xn" , Pft_fmt_itm_.Raw) // NOTE: really does nothing; REF.MW: Language.php|sprintfdate does $s .= $num; DATE:2013-12-31
.Add("xN" , Pft_fmt_itm_.Raw)
.Add("xjj" , Pft_fmt_itm_.Hebrew_day_num)
.Add("xjn" , Pft_fmt_itm_.Hebrew_month_num)
.Add("xjt" , Pft_fmt_itm_.Hebrew_month_days_count)
.Add("xjF" , Pft_fmt_itm_.Hebrew_month_name_full)
.Add("xjx" , Pft_fmt_itm_.Hebrew_month_name_gen)
.Add("xjY" , Pft_fmt_itm_.Hebrew_year_num)
.Add("xh" , Pft_fmt_itm_.Hebrew_numeral)
// TODO: foreign; space; "
;
public static Pft_fmt_itm[] Parse(Xop_ctx ctx, byte[] fmt) {
Btrie_fast_mgr trie = Pft_fmt_itm_.Regy;
int i = 0, fmt_len = fmt.length;
fmt_itms.Clear(); int raw_bgn = String_.Pos_neg1; byte raw_byt = Byte_.Zero;
while (i < fmt_len) {
byte b = fmt[i];
Object o = trie.Match_bgn_w_byte(b, fmt, i, fmt_len);
if (o != null) {
if (raw_bgn != String_.Pos_neg1) {fmt_itms.Add(i - raw_bgn == 1 ? new Pft_fmt_itm_raw_byt(raw_byt) : (Pft_fmt_itm)new Pft_fmt_itm_raw_ary(fmt, raw_bgn, i)); raw_bgn = String_.Pos_neg1;}
fmt_itms.Add((Pft_fmt_itm)o);
i = trie.Match_pos();
}
else {
switch (b) {
case Byte_ascii.Backslash:
if (raw_bgn != String_.Pos_neg1) {fmt_itms.Add(i - raw_bgn == 1 ? new Pft_fmt_itm_raw_byt(raw_byt) : (Pft_fmt_itm)new Pft_fmt_itm_raw_ary(fmt, raw_bgn, i)); raw_bgn = String_.Pos_neg1;}
++i; // peek next char
if (i == fmt_len) // trailing backslash; add one; EX: "b\" -> "b\" not "b"
fmt_itms.Add(new Pft_fmt_itm_raw_byt(Byte_ascii.Backslash));
else
fmt_itms.Add(new Pft_fmt_itm_raw_byt(fmt[i]));
++i;
break;
case Byte_ascii.Quote:
if (raw_bgn != String_.Pos_neg1) {fmt_itms.Add(i - raw_bgn == 1 ? new Pft_fmt_itm_raw_byt(raw_byt) : (Pft_fmt_itm)new Pft_fmt_itm_raw_ary(fmt, raw_bgn, i)); raw_bgn = String_.Pos_neg1;}
++i; // skip quote_bgn
raw_bgn = i;
while (i < fmt_len) {
b = fmt[i];
if (b == Byte_ascii.Quote) {
break;
}
else
++i;
}
fmt_itms.Add(i - raw_bgn == 0 ? new Pft_fmt_itm_raw_byt(Byte_ascii.Quote) : (Pft_fmt_itm)new Pft_fmt_itm_raw_ary(fmt, raw_bgn, i));
raw_bgn = String_.Pos_neg1;
++i; // skip quote_end
break;
default:
if (raw_bgn == String_.Pos_neg1) {raw_bgn = i; raw_byt = b;}
i += gplx.intl.Utf8_.Len_of_char_by_1st_byte(b);
break;
}
}
}
if (raw_bgn != String_.Pos_neg1) {fmt_itms.Add(fmt_len - raw_bgn == 1 ? new Pft_fmt_itm_raw_byt(fmt[fmt_len - 1]) : (Pft_fmt_itm)new Pft_fmt_itm_raw_ary(fmt, raw_bgn, fmt_len)); raw_bgn = String_.Pos_neg1;}
return (Pft_fmt_itm[])fmt_itms.To_ary(Pft_fmt_itm.class);
} private static List_adp fmt_itms = List_adp_.new_();
}

View File

@@ -0,0 +1,334 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
class Pft_fmt_itm_roman implements Pft_fmt_itm {
public int TypeId() {return Pft_fmt_itm_.Tid_roman;}
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
int nxt_idx = bldr.Idx_cur() + 1;
Pft_fmt_itm[] ary = bldr.Fmt_itms();
if (nxt_idx < ary.length) {
Pft_fmt_itm itm = (Pft_fmt_itm)ary[nxt_idx];
if (itm.TypeId() == Pft_fmt_itm_.Tid_seg_int) {
Pft_fmt_itm_seg_int nxt_int = (Pft_fmt_itm_seg_int)ary[nxt_idx]; // FUTURE: should check tkn type
int v = date.Segment(nxt_int.SegIdx());
Pfxtp_roman.ToRoman(v, bfr);
bldr.Idx_nxt_(nxt_idx + 1);
return;
}
}
bfr.Add_str_a7("xf");
}
}
class Pft_fmt_itm_thai implements Pft_fmt_itm {
public int TypeId() {return Pft_fmt_itm_.Tid_thai;}
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
bfr.Add_int_variable(date.Year() + 543);
}
}
class Pft_fmt_itm_minguo implements Pft_fmt_itm {
public int TypeId() {return Pft_fmt_itm_.Tid_minguo;}
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
bfr.Add_int_variable(date.Year() - 1911);
}
}
class Pft_fmt_itm_hebrew_year_num implements Pft_fmt_itm {
public int TypeId() {return Pft_fmt_itm_.Tid_hebrew_year_num;}
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
int[] hebrew_date = Pft_fmt_itm_hebrew_.Calc_hebrew_date(date);
bfr.Add_int_variable(hebrew_date[Pft_fmt_itm_hebrew_.Rslt_year_num]);
}
}
class Pft_fmt_itm_hebrew_month_num implements Pft_fmt_itm {
public int TypeId() {return Pft_fmt_itm_.Tid_hebrew_month_num;}
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
int[] hebrew_date = Pft_fmt_itm_hebrew_.Calc_hebrew_date(date);
bfr.Add_int_variable(hebrew_date[Pft_fmt_itm_hebrew_.Rslt_month_num]);
}
}
class Pft_fmt_itm_hebrew_day_num implements Pft_fmt_itm {
public int TypeId() {return Pft_fmt_itm_.Tid_hebrew_day_num;}
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
int[] hebrew_date = Pft_fmt_itm_hebrew_.Calc_hebrew_date(date);
bfr.Add_int_variable(hebrew_date[Pft_fmt_itm_hebrew_.Rslt_day_num]);
}
}
class Pft_fmt_itm_hebrew_month_days_count implements Pft_fmt_itm {
public int TypeId() {return Pft_fmt_itm_.Tid_hebrew_month_days_count;}
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
int[] hebrew_date = Pft_fmt_itm_hebrew_.Calc_hebrew_date(date);
bfr.Add_int_variable(hebrew_date[Pft_fmt_itm_hebrew_.Rslt_month_days_count]);
}
}
class Pft_fmt_itm_hebrew_month_name_full implements Pft_fmt_itm {
public int TypeId() {return Pft_fmt_itm_.Tid_hebrew_month_name_full;}
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
bfr.Add(Pft_fmt_itm_hebrew_.Get_hebrew_month_name_full(wiki, date));
}
}
class Pft_fmt_itm_hebrew_month_name_gen implements Pft_fmt_itm {
public int TypeId() {return Pft_fmt_itm_.Tid_hebrew_month_name_gen;}
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
bfr.Add(Pft_fmt_itm_hebrew_.Get_hebrew_month_name_gen(wiki, date));
}
}
class Pft_fmt_itm_hebrew_numeral implements Pft_fmt_itm {
public int TypeId() {return Pft_fmt_itm_.Tid_hebrew_numeral;}
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
bfr.Add_str(Pft_fmt_itm_hebrew_.Calc_hebrew_numeral(date.Year()));
}
}
class Pft_fmt_itm_hebrew_ {
public static int Calc_hebrew_year_num_start(int year) {
int year_minus_1 = year - 1;
int a = (12 * year_minus_1 + 17) % 19;
int b = year_minus_1 % 4;
double m = 32.044093161144d + 1.5542417966212d * a + b / 4.0 - 0.0031777940220923d * year_minus_1;
if (m < 0)
m--;
int mar = (int)m;
if (m < 0)
m++;
m -= mar;
int c = (mar + 3 * year_minus_1 + 5 * b + 5) % 7;
if (c == 0 && a > 11 && m >= 0.89772376543210d)
mar++;
else if (c == 1 && a > 6 && m >= 0.63287037037037d)
mar += 2;
else if (c == 2 || c == 4 || c == 6)
mar++;
double year_minus_3761 = year - 3761;
mar += (int)(year_minus_3761 / 100 ) - (int)(year_minus_3761 / 400) - 24;
return mar;
}
private static final int[] Hebrew_date_rslt = new int[4];
public static int[] Calc_hebrew_date(DateAdp date) {
synchronized (Hebrew_date_rslt) {
Calc_hebrew_date(Hebrew_date_rslt, date.Year(), date.Month(), date.Day());
return Hebrew_date_rslt;
}
}
public static boolean Calc_hebrew_date(int[] rv, int year, int month, int day) { // REF.MW:Language.php|tsToHebrew
// Calculate Hebrew year
int hebrewYear = year + 3760;
// Month number when September = 1, August = 12
month += 4;
if (month > 12) {
// Next year
month -= 12;
year++;
hebrewYear++;
}
// Calculate day of year from 1 September
int dayOfYear = day;
for (int i = 1; i < month; i++) {
if (i == 6) {
// February
dayOfYear += 28;
// Check if the year is leap
if (year % 400 == 0 || (year % 4 == 0 && year % 100 > 0)) {
dayOfYear++;
}
} else if (i == 8 || i == 10 || i == 1 || i == 3) {
dayOfYear += 30;
} else {
dayOfYear += 31;
}
}
// Calculate the start of the Hebrew year
int start = Calc_hebrew_year_num_start(hebrewYear);
// Calculate next year's start
int nextStart = 0;
if (dayOfYear <= start) {
// Day is before the start of the year - it is the previous year
// Next year's start
nextStart = start;
// Previous year
year--;
hebrewYear--;
// Add days since previous year's 1 September
dayOfYear += 365;
if ((year % 400 == 0) || (year % 100 != 0 && year % 4 == 0)) {
// Leap year
dayOfYear++;
}
// Start of the new (previous) year
start = Calc_hebrew_year_num_start(hebrewYear);
} else {
// Next year's start
nextStart = Calc_hebrew_year_num_start(hebrewYear + 1);
}
// Calculate Hebrew day of year
int hebrewDayOfYear = dayOfYear - start;
// Difference between year's days
int diff = nextStart - start;
// Add 12 (or 13 for leap years) days to ignore the difference between
// Hebrew and Gregorian year (353 at least vs. 365/6) - now the
// difference is only about the year type
if ((year % 400 == 0) || (year % 100 != 0 && year % 4 == 0)) {
diff += 13;
} else {
diff += 12;
}
// Check the year pattern, and is leap year
// 0 means an incomplete year, 1 means a regular year, 2 means a complete year
// This is mod 30, to work on both leap years (which add 30 days of Adar I)
// and non-leap years
int yearPattern = diff % 30;
// Check if leap year
boolean isLeap = diff >= 30;
// Calculate day in the month from number of day in the Hebrew year
// Don't check Adar - if the day is not in Adar, we will stop before;
// if it is in Adar, we will use it to check if it is Adar I or Adar II
int hebrewDay = hebrewDayOfYear;
int hebrewMonth = 1;
int days = 0;
while (hebrewMonth <= 12) {
// Calculate days in this month
if (isLeap && hebrewMonth == 6) {
// Adar in a leap year
if (isLeap) {
// Leap year - has Adar I, with 30 days, and Adar II, with 29 days
days = 30;
if (hebrewDay <= days) {
// Day in Adar I
hebrewMonth = 13;
} else {
// Subtract the days of Adar I
hebrewDay -= days;
// Try Adar II
days = 29;
if (hebrewDay <= days) {
// Day in Adar II
hebrewMonth = 14;
}
}
}
} else if (hebrewMonth == 2 && yearPattern == 2) {
// Cheshvan in a complete year (otherwise as the rule below)
days = 30;
} else if (hebrewMonth == 3 && yearPattern == 0) {
// Kislev in an incomplete year (otherwise as the rule below)
days = 29;
} else {
// Odd months have 30 days, even have 29
days = 30 - (hebrewMonth - 1) % 2;
}
if (hebrewDay <= days) {
// In the current month
break;
} else {
// Subtract the days of the current month
hebrewDay -= days;
// Try in the next month
hebrewMonth++;
}
}
rv[0] = hebrewYear;
rv[1] = hebrewMonth;
rv[2] = hebrewDay;
rv[3] = days;
return true;
}
public static byte[] Get_hebrew_month_name_full(Xowe_wiki wiki, DateAdp date) {return Get_hebrew_month_name(wiki, date, Month_name_full_ary);}
public static byte[] Get_hebrew_month_name_gen(Xowe_wiki wiki, DateAdp date) {return Get_hebrew_month_name(wiki, date, Month_name_gen_ary);}
private static byte[] Get_hebrew_month_name(Xowe_wiki wiki, DateAdp date, byte[][] name_ary) {
int[] hebrew_date = Pft_fmt_itm_hebrew_.Calc_hebrew_date(date);
int hebrew_month = hebrew_date[Pft_fmt_itm_hebrew_.Rslt_month_num] - List_adp_.Base1;
byte[] msg_key = name_ary[hebrew_month];
return wiki.Msg_mgr().Val_by_key_obj(msg_key);
}
private static final byte[][] Month_name_full_ary = new byte[][]
{ Bry_.new_a7("hebrew-calendar-m1"), Bry_.new_a7("hebrew-calendar-m2"), Bry_.new_a7("hebrew-calendar-m3")
, Bry_.new_a7("hebrew-calendar-m4"), Bry_.new_a7("hebrew-calendar-m5"), Bry_.new_a7("hebrew-calendar-m6")
, Bry_.new_a7("hebrew-calendar-m7"), Bry_.new_a7("hebrew-calendar-m8"), Bry_.new_a7("hebrew-calendar-m9")
, Bry_.new_a7("hebrew-calendar-m10"), Bry_.new_a7("hebrew-calendar-m11"), Bry_.new_a7("hebrew-calendar-m12")
, Bry_.new_a7("hebrew-calendar-m6a"), Bry_.new_a7("hebrew-calendar-m6b")
};
private static final byte[][] Month_name_gen_ary = new byte[][]
{ Bry_.new_a7("hebrew-calendar-m1-gen"), Bry_.new_a7("hebrew-calendar-m2-gen"), Bry_.new_a7("hebrew-calendar-m3-gen")
, Bry_.new_a7("hebrew-calendar-m4-gen"), Bry_.new_a7("hebrew-calendar-m5-gen"), Bry_.new_a7("hebrew-calendar-m6-gen")
, Bry_.new_a7("hebrew-calendar-m7-gen"), Bry_.new_a7("hebrew-calendar-m8-gen"), Bry_.new_a7("hebrew-calendar-m9-gen")
, Bry_.new_a7("hebrew-calendar-m10-gen"), Bry_.new_a7("hebrew-calendar-m11-gen"), Bry_.new_a7("hebrew-calendar-m12-gen")
, Bry_.new_a7("hebrew-calendar-m6a-gen"), Bry_.new_a7("hebrew-calendar-m6b-gen")
};
public static final int
Rslt_year_num = 0
, Rslt_month_num = 1
, Rslt_day_num = 2
, Rslt_month_days_count = 3
;
private static final String[][] Numeral_tbls = new String[][]
{ new String[] {"", "א", "ב", "ג", "ד", "ה", "ו", "ז", "ח", "ט", "י"}
, new String[] {"", "י", "כ", "ל", "מ", "נ", "ס", "ע", "פ", "צ", "ק"}
, new String[] {"", "ק", "ר", "ש", "ת", "תק", "תר", "תש", "תת", "תתק", "תתר"}
, new String[] {"", "א", "ב", "ג", "ד", "ה", "ו", "ז", "ח", "ט", "י"}
};
public static String Calc_hebrew_numeral(int num) {
if (num > 9999 || num <= 0)
return Int_.Xto_str(num);
String tmp = "";
int pow10 = 1000;
for (int i = 3; i >= 0; pow10 /= 10, i--) {
if (num >= pow10) {
if (num == 15 || num == 16) {
tmp += Numeral_tbls[0][9] + Numeral_tbls[0][num - 9];
num = 0;
} else {
tmp += Numeral_tbls[i][(int)(num / pow10)];
if (pow10 == 1000)
tmp += "'";
}
}
num = num % pow10;
}
String rv = "";
int tmp_len = String_.Len(tmp);
if (tmp_len == 2) {
rv = tmp + "'";
}
else {
rv = String_.Mid(tmp, 0, tmp_len - 1) + "\"";
rv += String_.Mid(tmp, tmp_len - 1);
}
int rv_len = String_.Len(rv);
String start = String_.Mid(rv, 0, rv_len - 1);
String end = String_.Mid(rv, rv_len - 1);
if (String_.Eq(end, "כ"))
rv = start + "ך";
else if (String_.Eq(end, "מ"))
rv = start + "ם";
else if (String_.Eq(end, "נ"))
rv = start + "ן";
else if (String_.Eq(end, "פ"))
rv = start + "ף";
else if (String_.Eq(end, "צ"))
rv = start + "ץ";
return rv;
}
}

View File

@@ -0,0 +1,130 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
class Pft_fmt_itm_seg_int implements Pft_fmt_itm {
public Pft_fmt_itm_seg_int(int segIdx, int len, boolean fixed_len) {this.segIdx = segIdx; this.fixed_len = fixed_len; this.len = len;} private int segIdx, len; boolean fixed_len;
public int TypeId() {return Pft_fmt_itm_.Tid_seg_int;}
public int SegIdx() {return segIdx;}
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
int val = date.Segment(segIdx);
if (fixed_len) bfr.Add_int_fixed(val, len);
else bfr.Add_int_variable(val);
}
}
class Pft_fmt_itm_raw implements Pft_fmt_itm {
public int TypeId() {return Pft_fmt_itm_.Tid_raw;}
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
// TODO: should flag .Raw() on bldr to skip transliterating numerals in foreign languages; DATE:2013-12-31
}
}
class Pft_fmt_itm_seg_str implements Pft_fmt_itm {
public Pft_fmt_itm_seg_str(int segIdx, int type) {this.segIdx = segIdx; this.type = type;} private int segIdx, type;
public int TypeId() {return Pft_fmt_itm_.Tid_seg_str;}
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
DateAdpTranslator_xapp.Translate(wiki, lang, type, date.Segment(segIdx), bfr);
}
}
class Pft_fmt_itm_year_isLeap implements Pft_fmt_itm {
public int TypeId() {return Pft_fmt_itm_.Tid_year_isLeap;}
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {bfr.Add_int_fixed(DateAdp_.IsLeapYear(date.Year()) ? 1 : 0, 1);}
}
class Pft_fmt_itm_hour_base12 implements Pft_fmt_itm {
public int TypeId() {return Pft_fmt_itm_.Tid_hour_base12;}
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
int val = date.Hour();
switch (val) {
case 0: val = 12; break;
case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: val -= 12; break;
default: break;
}
if (fixed_len) bfr.Add_int_fixed(val, 2);
else bfr.Add_int_variable(val);
}
public Pft_fmt_itm_hour_base12(boolean fixed_len) {this.fixed_len = fixed_len;} private boolean fixed_len;
}
class Pft_fmt_itm_timestamp_unix implements Pft_fmt_itm {
public int TypeId() {return Pft_fmt_itm_.Tid_timestamp_unix;}
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {bfr.Add_long_variable(date.Timestamp_unix());}
}
class Pft_fmt_itm_raw_ary implements Pft_fmt_itm {
public int TypeId() {return Pft_fmt_itm_.Tid_raw_ary;}
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {bfr.Add_mid(src, bgn, end);}
public Pft_fmt_itm_raw_ary(byte[] src, int bgn, int end) {this.src = src; this.bgn = bgn; this.end = end;} private byte[] src; int bgn; int end;
}
class Pft_fmt_itm_raw_byt implements Pft_fmt_itm {
public int TypeId() {return Pft_fmt_itm_.Tid_raw_byt;}
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {bfr.Add_byte(b);}
public Pft_fmt_itm_raw_byt(byte b) {this.b = b;} private byte b;
}
class Pft_fmt_itm_daysInMonth implements Pft_fmt_itm {
public int TypeId() {return Pft_fmt_itm_.Tid_daysInMonth;}
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {bfr.Add_int_variable(DateAdp_.DaysInMonth(date));}
}
class Pft_fmt_itm_dayOfYear implements Pft_fmt_itm {
public int TypeId() {return Pft_fmt_itm_.Tid_dayOfYear;}
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {bfr.Add_int_variable(date.DayOfYear() - Int_.Base1);} // php is base1; .net/java is base0
}
class Pft_fmt_itm_am_pm implements Pft_fmt_itm {
public int TypeId() {return Pft_fmt_itm_.Tid_AmPm;}
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
boolean am = date.Hour() < 13;
byte[] val = null;
if ( am && lower) val = Ary_am_lower;
else if ( am && !lower) val = Ary_am_upper;
else if (!am && lower) val = Ary_pm_lower;
else if (!am && !lower) val = Ary_pm_upper;
bfr.Add(val);
} static final byte[] Ary_am_upper = Bry_.new_a7("AM"), Ary_pm_upper = Bry_.new_a7("PM"), Ary_am_lower = Bry_.new_a7("am"), Ary_pm_lower = Bry_.new_a7("pm");
public Pft_fmt_itm_am_pm(boolean lower) {this.lower = lower;} private boolean lower;
}
class Pft_fmt_itm_dow_base0 implements Pft_fmt_itm {
public int TypeId() {return Pft_fmt_itm_.Tid_dow_base0;}
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
int dow = date.DayOfWeek();
if (dow == 0) dow = 7;
bfr.Add_int_fixed(dow, 1);
}
}
class Pft_fmt_itm_iso_fmt implements Pft_fmt_itm {
public Pft_fmt_itm_iso_fmt() {}
public int TypeId() {return Pft_fmt_itm_.Tid_iso_fmt;}
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
bfr.Add_str(date.XtoStr_fmt("yyyy-MM-dd"));
bfr.Add_byte(Byte_ascii.Ltr_T);
bfr.Add_str(date.XtoStr_fmt("HH:mm:ss"));
bfr.Add_str(date.XtoStr_tz());
}
}
class Pft_fmt_itm_rfc_5322 implements Pft_fmt_itm {
public Pft_fmt_itm_rfc_5322() {}
public int TypeId() {return Pft_fmt_itm_.Tid_rfc_5322;}
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {// Mon, 02 Jan 2012 10:15:01 +0000
int dow = date.DayOfWeek();
DateAdpTranslator_xapp.Translate(wiki, lang, DateAdp_.SegIdx_dayOfWeek, dow, bfr);
bfr.Add_byte(Byte_ascii.Comma).Add_byte(Byte_ascii.Space);
bfr.Add_str(date.XtoStr_fmt("dd MMM yyyy HH:mm:ss")); // NOTE: always UTC time
bfr.Add(CONST_timezone); // NOTE: always UTC time zone
} static final byte[] CONST_timezone = Bry_.new_a7(" +0000");
}
class Pft_fmt_itm_timezone_offset implements Pft_fmt_itm {
public Pft_fmt_itm_timezone_offset() {}
public int TypeId() {return Pft_fmt_itm_.Tid_timezone_offset;}
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
bfr.Add_int_variable(date.Timezone_offset());
}
}

View File

@@ -0,0 +1,92 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
public class Pft_func_date_int extends Pf_func_base {
public Pft_func_date_int(int id, int date_tid) {this.id = id; this.date_tid = date_tid;} private int date_tid;
@Override public int Id() {return id;} private int id;
@Override public Pf_func New(int id, byte[] name) {return new Pft_func_date_int(id, date_tid).Name_(name);}
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bfr) {
DateAdp date = DateAdp_.MinValue;
Xowe_wiki wiki = ctx.Wiki(); Xol_lang lang = ctx.Lang();
switch (date_tid) {
case Date_tid_lcl: date = DateAdp_.Now(); break;
case Date_tid_utc: date = DateAdp_.Now().XtoUtc(); break;
case Date_tid_rev: date = ctx.Cur_page().Revision_data().Modified_on(); break;
default: throw Exc_.new_unhandled(date_tid);
}
switch (id) {
case Xol_kwd_grp_.Id_utc_year:
case Xol_kwd_grp_.Id_lcl_year:
case Xol_kwd_grp_.Id_rev_year:
Pft_func_formatdate.Date_bldr().Format(bfr, wiki, lang, date, Pft_fmt_itm_.Year_len4);
break;
case Xol_kwd_grp_.Id_utc_month_int_len2:
case Xol_kwd_grp_.Id_lcl_month_int_len2:
case Xol_kwd_grp_.Id_rev_month_int_len2:
Pft_func_formatdate.Date_bldr().Format(bfr, wiki, lang, date, Pft_fmt_itm_.Month_int_len2);
break;
case Xol_kwd_grp_.Id_utc_month_int:
case Xol_kwd_grp_.Id_lcl_month_int:
case Xol_kwd_grp_.Id_rev_month_int:
Pft_func_formatdate.Date_bldr().Format(bfr, wiki, lang, date, Pft_fmt_itm_.Month_int);
break;
case Xol_kwd_grp_.Id_utc_day_int_len2:
case Xol_kwd_grp_.Id_lcl_day_int_len2:
case Xol_kwd_grp_.Id_rev_day_int_len2:
Pft_func_formatdate.Date_bldr().Format(bfr, wiki, lang, date, Pft_fmt_itm_.Day_int_len2);
break;
case Xol_kwd_grp_.Id_utc_day_int:
case Xol_kwd_grp_.Id_lcl_day_int:
case Xol_kwd_grp_.Id_rev_day_int:
Pft_func_formatdate.Date_bldr().Format(bfr, wiki, lang, date, Pft_fmt_itm_.Day_int);
break;
case Xol_kwd_grp_.Id_lcl_hour:
case Xol_kwd_grp_.Id_utc_hour:
Pft_func_formatdate.Date_bldr().Format(bfr, wiki, lang, date, Pft_fmt_itm_.Hour_base24_len2);
break;
case Xol_kwd_grp_.Id_lcl_dow:
case Xol_kwd_grp_.Id_utc_dow:
Pft_func_formatdate.Date_bldr().Format(bfr, wiki, lang, date, Pft_fmt_itm_.Dow_base1_int);
break;
case Xol_kwd_grp_.Id_lcl_week:
case Xol_kwd_grp_.Id_utc_week:
Pft_func_formatdate.Date_bldr().Format(bfr, wiki, lang, date, Pft_fmt_itm_.WeekOfYear_int);
break;
case Xol_kwd_grp_.Id_lcl_time:
case Xol_kwd_grp_.Id_utc_time: // 17:29
bfr.Add_int_fixed(date.Hour(), 2).Add_byte(Byte_ascii.Colon).Add_int_fixed(date.Minute(), 2);
break;
case Xol_kwd_grp_.Id_lcl_timestamp:
case Xol_kwd_grp_.Id_utc_timestamp:
case Xol_kwd_grp_.Id_rev_timestamp: // 20120123172956
bfr .Add_int_fixed(date.Year() , 4)
.Add_int_fixed(date.Month() , 2)
.Add_int_fixed(date.Day() , 2)
.Add_int_fixed(date.Hour() , 2)
.Add_int_fixed(date.Minute(), 2)
.Add_int_fixed(date.Second(), 2);
break;
default: throw Exc_.new_unhandled(id);
}
}
public static final int Date_tid_utc = 0, Date_tid_lcl = 1, Date_tid_rev = 2;
public static final Pft_func_date_int
Utc = new Pft_func_date_int(-1, Date_tid_utc)
, Lcl = new Pft_func_date_int(-1, Date_tid_lcl)
, Rev = new Pft_func_date_int(-1, Date_tid_rev);
}

View File

@@ -0,0 +1,37 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
import org.junit.*;
public class Pft_func_date_lcl_tst {
private Xop_fxt fxt = new Xop_fxt();
@Before public void setup() {fxt.Reset(); Tfds.Now_set(DateAdp_.new_(2012, 1, 2, 3, 4, 5, 6));}
@After public void teardown() {Tfds.Now_enabled_n_();}
@Test public void Lcl_year() {fxt.Test_parse_tmpl_str_test("{{LOCALYEAR}}" , "{{test}}", "2012");}
@Test public void Lcl_month_int() {fxt.Test_parse_tmpl_str_test("{{LOCALMONTH1}}" , "{{test}}", "1");}
@Test public void Lcl_month_int_len2() {fxt.Test_parse_tmpl_str_test("{{LOCALMONTH}}" , "{{test}}", "01");}
@Test public void Lcl_day_int() {fxt.Test_parse_tmpl_str_test("{{LOCALDAY}}" , "{{test}}", "2");}
@Test public void Lcl_day_int_len2() {fxt.Test_parse_tmpl_str_test("{{LOCALDAY2}}" , "{{test}}", "02");}
@Test public void Lcl_day_hour_len2() {fxt.Test_parse_tmpl_str_test("{{LOCALHOUR}}" , "{{test}}", "03");}
@Test public void Lcl_dow_int() {fxt.Test_parse_tmpl_str_test("{{LOCALDOW}}" , "{{test}}", "1");}
@Test public void Lcl_week_int() {fxt.Test_parse_tmpl_str_test("{{LOCALWEEK}}" , "{{test}}", "1");}
@Test public void Lcl_month_name() {fxt.Test_parse_tmpl_str_test("{{LOCALMONTHNAME}}" , "{{test}}", "January");}
@Test public void Lcl_month_gen() {fxt.Test_parse_tmpl_str_test("{{LOCALMONTHNAMEGEN}}" , "{{test}}", "January");}
@Test public void Lcl_day_name() {fxt.Test_parse_tmpl_str_test("{{LOCALDAYNAME}}" , "{{test}}", "Monday");}
@Test public void Lcl_time() {fxt.Test_parse_tmpl_str_test("{{LOCALTIME}}" , "{{test}}", "03:04");}
@Test public void Lcl_timestamp() {fxt.Test_parse_tmpl_str_test("{{LOCALTIMESTAMP}}" , "{{test}}", "20120102030405");}
}

View File

@@ -0,0 +1,35 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
public class Pft_func_date_name extends Pf_func_base {
public Pft_func_date_name(int id, int date_tid, int seg_idx, int base_idx) {this.id = id; this.date_tid = date_tid; this.seg_idx = seg_idx; this.base_idx = base_idx;} private int date_tid, seg_idx, base_idx;
@Override public int Id() {return id;} private int id;
@Override public Pf_func New(int id, byte[] name) {return new Pft_func_date_name(id, date_tid, seg_idx, base_idx).Name_(name);}
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bfr) {
DateAdp date = DateAdp_.MinValue;
switch (date_tid) {
case Pft_func_date_int.Date_tid_lcl: date = DateAdp_.Now(); break;
case Pft_func_date_int.Date_tid_utc: date = DateAdp_.Now().XtoUtc(); break;
case Pft_func_date_int.Date_tid_rev: date = ctx.Cur_page().Revision_data().Modified_on(); break;
default: throw Exc_.new_unhandled(date_tid);
}
byte[] val = ctx.Wiki().Msg_mgr().Val_by_id(base_idx + date.Segment(seg_idx));
bfr.Add(val);
// translator.Translate(base_idx, date.Segment(seg_idx), bfr);
}
}

View File

@@ -0,0 +1,30 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
import org.junit.*;
public class Pft_func_date_rev_tst {
private Xop_fxt fxt = new Xop_fxt();
@Before public void setup() {fxt.Reset(); fxt.Page().Revision_data().Modified_on_(DateAdp_.new_(2012, 1, 2, 3, 4, 5, 6));}
@After public void teardown() {}
@Test public void Rev_year() {fxt.Test_parse_tmpl_str_test("{{REVISIONYEAR}}" , "{{test}}", "2012");}
@Test public void Rev_month_int() {fxt.Test_parse_tmpl_str_test("{{REVISIONMONTH1}}" , "{{test}}", "1");}
@Test public void Rev_month_int_len2() {fxt.Test_parse_tmpl_str_test("{{REVISIONMONTH}}" , "{{test}}", "01");}
@Test public void Rev_day_int() {fxt.Test_parse_tmpl_str_test("{{REVISIONDAY}}" , "{{test}}", "2");}
@Test public void Rev_day_int_len2() {fxt.Test_parse_tmpl_str_test("{{REVISIONDAY2}}" , "{{test}}", "02");}
@Test public void Rev_timestamp() {fxt.Test_parse_tmpl_str_test("{{REVISIONTIMESTAMP}}" , "{{test}}", "20120102030405");}
}

View File

@@ -0,0 +1,38 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
import org.junit.*;
public class Pft_func_date_utc_tst {
private Xop_fxt fxt = new Xop_fxt();
@Before public void setup() {fxt.Reset(); Tfds.Now_set(DateAdp_.new_(2011, 12, 31, 22, 4, 5, 6));} // ENV:Assumes Eastern Standard Time (-5)
@After public void teardown() {Tfds.Now_enabled_n_();}
@Test public void Utc_year() {fxt.Test_parse_tmpl_str_test("{{CURRENTYEAR}}" , "{{test}}", "2012");}
@Test public void Utc_month_int() {fxt.Test_parse_tmpl_str_test("{{CURRENTMONTH1}}" , "{{test}}", "1");}
@Test public void Utc_month_int_len2() {fxt.Test_parse_tmpl_str_test("{{CURRENTMONTH}}" , "{{test}}", "01");}
@Test public void Utc_day_int() {fxt.Test_parse_tmpl_str_test("{{CURRENTDAY}}" , "{{test}}", "1");}
@Test public void Utc_day_int_len2() {fxt.Test_parse_tmpl_str_test("{{CURRENTDAY2}}" , "{{test}}", "01");}
@Test public void Utc_day_hour_len2() {fxt.Test_parse_tmpl_str_test("{{CURRENTHOUR}}" , "{{test}}", "03");}
@Test public void Utc_dow_int() {fxt.Test_parse_tmpl_str_test("{{CURRENTDOW}}" , "{{test}}", "0");}
@Test public void Utc_week_int() {fxt.Test_parse_tmpl_str_test("{{CURRENTWEEK}}" , "{{test}}", "1");}
@Test public void Utc_month_abrv() {fxt.Test_parse_tmpl_str_test("{{CURRENTMONTHABBREV}}" , "{{test}}", "Jan");}
@Test public void Utc_month_name() {fxt.Test_parse_tmpl_str_test("{{CURRENTMONTHNAME}}" , "{{test}}", "January");}
@Test public void Utc_month_gen() {fxt.Test_parse_tmpl_str_test("{{CURRENTMONTHNAMEGEN}}" , "{{test}}", "January");}
@Test public void Utc_day_name() {fxt.Test_parse_tmpl_str_test("{{CURRENTDAYNAME}}" , "{{test}}", "Sunday");}
@Test public void Utc_time() {fxt.Test_parse_tmpl_str_test("{{CURRENTTIME}}" , "{{test}}", "03:04");}
@Test public void Utc_timestamp() {fxt.Test_parse_tmpl_str_test("{{CURRENTTIMESTAMP}}" , "{{test}}", "20120101030405");}
}

View File

@@ -0,0 +1,49 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
import gplx.core.btries.*;
public class Pft_func_formatdate extends Pf_func_base {
@Override public int Id() {return Xol_kwd_grp_.Id_str_formatdate;}
@Override public Pf_func New(int id, byte[] name) {return new Pft_func_formatdate().Name_(name);}
@Override public boolean Func_require_colon_arg() {return true;}
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bfr) {
int self_args_len = self.Args_len();
byte[] date_bry = Eval_argx(ctx, src, caller, self);
byte[] fmt_bry = Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self_args_len, 0);
if (fmt_bry == Bry_.Empty) {bfr.Add(date_bry); return;} // no format given; add self;
int fmt_bry_len = fmt_bry.length;
Object o = trie.Match_bgn(fmt_bry, 0, fmt_bry_len);
if (o == null
|| o == Fmt_itms_default) {// NOOP for default?
bfr.Add(date_bry);
return;
}
DateAdp date = Pft_func_time.ParseDate(date_bry, false, ctx.App().Utl__bfr_mkr().Get_b512().Mkr_rls());
if (date == null) {bfr.Add(date_bry); return;} // date not parseable; return self; DATE:2014-04-13
date_bldr.Format(bfr, ctx.Wiki(), ctx.Lang(), date, (Pft_fmt_itm[])o);
}
public static Pft_func_formatdate_bldr Date_bldr() {return date_bldr;} private static Pft_func_formatdate_bldr date_bldr = new Pft_func_formatdate_bldr();
private static final Pft_fmt_itm[] Fmt_itms_default = new Pft_fmt_itm[0];
private static final Btrie_fast_mgr trie = Btrie_fast_mgr.cs_()
.Add("dmy" , new Pft_fmt_itm[] {Pft_fmt_itm_.Day_int, Pft_fmt_itm_.Byte_space, Pft_fmt_itm_.Month_name, Pft_fmt_itm_.Byte_space, Pft_fmt_itm_.Year_len4})
.Add("mdy" , new Pft_fmt_itm[] {Pft_fmt_itm_.Month_name, Pft_fmt_itm_.Byte_space, Pft_fmt_itm_.Day_int, Pft_fmt_itm_.Byte_comma, Pft_fmt_itm_.Byte_space, Pft_fmt_itm_.Year_len4})
.Add("ymd" , new Pft_fmt_itm[] {Pft_fmt_itm_.Year_len4, Pft_fmt_itm_.Byte_space, Pft_fmt_itm_.Month_name, Pft_fmt_itm_.Byte_space, Pft_fmt_itm_.Day_int})
.Add("ISO 8601" , new Pft_fmt_itm[] {Pft_fmt_itm_.Year_len4, Pft_fmt_itm_.Byte_dash, Pft_fmt_itm_.Month_int_len2, Pft_fmt_itm_.Byte_dash, Pft_fmt_itm_.Day_int_len2})
.Add("default" , Fmt_itms_default)
;
}

View File

@@ -0,0 +1,53 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
public class Pft_func_formatdate_bldr {
public int Idx_cur() {return idx_cur;} private int idx_cur;
public Pft_func_formatdate_bldr Idx_nxt_(int v) {idx_nxt = v; return this;} private int idx_nxt;
public Pft_fmt_itm[] Fmt_itms() {return fmt_itms;} Pft_fmt_itm[] fmt_itms;
public void Format(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_fmt_itm fmt_itm) {
fmt_itm.Fmt(bfr, wiki, lang, date, this);
}
public void Format(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_fmt_itm[] fmt_itms) {
this.fmt_itms = fmt_itms;
int len = fmt_itms.length;
idx_cur = 0; idx_nxt = -1;
Pft_fmt_itm last = null;
while (idx_cur < len) {
Pft_fmt_itm fmt_itm = fmt_itms[idx_cur];
if (fmt_itm.TypeId() == Pft_fmt_itm_.Tid_hebrew_numeral)
last = fmt_itm;
else {
fmt_itm.Fmt(bfr, wiki, lang, date, this);
}
if (idx_nxt == -1)
++idx_cur;
else {
idx_cur = idx_nxt;
idx_nxt = -1;
}
}
if (last != null) {
int year_int = bfr.XtoIntAndClear(-1);
if (year_int != -1) { // handle no format; EX:{{#time:xh}} DATE:2014-07-20
date = DateAdp_.seg_(new int[] {year_int, date.Month(), date.Day(), date.Hour(), date.Minute(), date.Second(), date.Frac()});
last.Fmt(bfr, wiki, lang, date, this);
}
}
}
}

View File

@@ -0,0 +1,38 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
import org.junit.*;
public class Pft_func_formatdate_tst {
private Xop_fxt fxt = new Xop_fxt();
@Before public void init() {fxt.Reset();}
@Test public void Fmt_dmy() {fxt.Test_parse_tmpl_str_test("{{#formatdate:2012-01-02|dmy}}" , "{{test}}" , "2 January 2012");}
@Test public void Fmt_mdy() {fxt.Test_parse_tmpl_str_test("{{#formatdate:2012-01-02|mdy}}" , "{{test}}" , "January 2, 2012");}
@Test public void Fmt_ymd() {fxt.Test_parse_tmpl_str_test("{{#formatdate:2012-01-02|ymd}}" , "{{test}}" , "2012 January 2");}
@Test public void Fmt_ISO_8601() {fxt.Test_parse_tmpl_str_test("{{#formatdate:2012-01-02|ISO 8601}}" , "{{test}}" , "2012-01-02");}
@Test public void Fmt_default() {fxt.Test_parse_tmpl_str_test("{{#formatdate:2012-01-02|default}}" , "{{test}}" , "2012-01-02");} // NOOP?
@Test public void Fmt_none() {fxt.Test_parse_tmpl_str_test("{{#formatdate:10 April 2012}}" , "{{test}}" , "10 April 2012");}
@Test public void Err_multiple_years() {fxt.Test_parse_tmpl_str_test("{{#formatdate:January 2, 1999, 2000|Y}}" , "{{test}}" , "January 2, 1999, 2000");} // PURPOSE: check that multiple years don't fail
@Test public void Unknown() {fxt.Test_parse_tmpl_str_test("{{#formatdate:unknown|dmy}}" , "{{test}}" , "unknown");} // PURPOSE: unknown term should output self, not ""; EX:w:Wikipedia:Wikipedia_Signpost/Newsroom/Opinion_desk/AdminCom; DATE:2014-04-13
}
/*
{{#formatdate:2012-01-02|dmy}}<br/>
{{#formatdate:2012-01-02|mdy}}<br/>
{{#formatdate:2012-01-02|ymd}}<br/>
{{#formatdate:2012-01-02|ISO 8601}}<br/>
{{#formatdate:2012-01-02|default}}<br/>
*/

View File

@@ -0,0 +1,95 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
import gplx.xowa.langs.*;
public class Pft_func_time extends Pf_func_base {
Pft_func_time(boolean utc) {this.utc = utc;} private boolean utc;
@Override public int Id() {return Xol_kwd_grp_.Id_xtn_time;}
@Override public Pf_func New(int id, byte[] name) {return new Pft_func_time(utc).Name_(name);}
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bfr) {// REF.MW:ParserFunctions_body.php
int self_args_len = self.Args_len();
byte[] arg_fmt = Eval_argx(ctx, src, caller, self);
Pft_fmt_itm[] fmt_ary = Pft_fmt_itm_.Parse(ctx, arg_fmt);
byte[] arg_date = Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self_args_len, 0);
byte[] arg_lang = Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self_args_len, 1);
Bry_bfr error_bfr = Bry_bfr.new_();
DateAdp date = ParseDate(arg_date, utc, error_bfr);
if (date == null || error_bfr.Len() > 0)
bfr.Add_str_a7("<strong class=\"error\">").Add_bfr_and_clear(error_bfr).Add_str("</strong>");
else {
Xol_lang lang = ctx.Lang();
if (Bry_.Len_gt_0(arg_lang)) {
Xol_lang_itm specified_lang_itm = Xol_lang_itm_.Get_by_key(arg_lang);
if (specified_lang_itm != null) { // NOTE: if lang_code is bad, then ignore (EX:bad_code)
Xol_lang specified_lang = ctx.Wiki().Appe().Lang_mgr().Get_by_key_or_new(arg_lang);
lang = specified_lang;
}
}
Pft_func_formatdate.Date_bldr().Format(bfr, ctx.Wiki(), lang, date, fmt_ary);
}
}
public static DateAdp ParseDate(byte[] date, boolean utc, Bry_bfr error_bfr) {
if (date == Bry_.Empty) return utc ? DateAdp_.Now().XtoUtc() : DateAdp_.Now();
try {
DateAdp rv = new Pxd_parser().Parse(date, error_bfr);
return rv;
}
catch (Exception exc) {
Exc_.Noop(exc);
error_bfr.Add_str_a7("Invalid time");
return null;
}
}
public static final Pft_func_time _Lcl = new Pft_func_time(false), _Utc = new Pft_func_time(true);
}
class DateAdpTranslator_xapp {
public static void Translate(Xowe_wiki wiki, Xol_lang lang, int type, int val, Bry_bfr bb) {
lang.Init_by_load_assert();
byte[] itm_val = lang.Msg_mgr().Val_by_id(type + val); if (itm_val == null) return;
bb.Add(itm_val);
}
}
class Pfxtp_roman {
public static void ToRoman(int num, Bry_bfr bfr) {
if (num > 3000 || num <= 0) {
bfr.Add_int_variable(num);
return;
}
int pow10 = 1000;
for (int i = 3; i > -1; i--) {
if (num >= pow10) {
bfr.Add(Names[i][Math_.Trunc(num / pow10)]);
}
num %= pow10;
pow10 /= 10;
}
}
private static byte[][][] Names = new byte[][][]
{ Bry_dim2_new_("", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X")
, Bry_dim2_new_("", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", "C")
, Bry_dim2_new_("", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM", "M")
, Bry_dim2_new_("", "M", "MM", "MMM")
};
private static byte[][] Bry_dim2_new_(String... names) {
int len = names.length;
byte[][] rv = new byte[len][];
for (int i = 0; i < len; i++)
rv[i] = Bry_.new_u8(names[i]);
return rv;
}
}

View File

@@ -0,0 +1,101 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
import org.junit.*;
public class Pft_func_time_basic_tst {
@Before public void init() {fxt.Reset(); Tfds.Now_set(DateAdp_.new_(2012, 1, 2, 3, 4, 5, 6));} private Xop_fxt fxt = new Xop_fxt();
@After public void term() {Tfds.Now_enabled_n_();}
@Test public void Utc_date() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|2012-01-02 03:04:05}}" , "2012-01-02");}
@Test public void Utc_time() {fxt.Test_parse_tmpl_str("{{#time:h:i:s A|2012-01-02 03:04:05}}" , "03:04:05 AM");}
@Test public void Utc_dayOfYear() {fxt.Test_parse_tmpl_str("{{#time:z|2012-01-01 03:04:05}}" , "0");}
@Test public void Utc_escape_basic() {fxt.Test_parse_tmpl_str("{{#time:\\Y Y|2012-01-02 03:04:05}}" , "Y 2012");}
@Test public void Utc_escape_double() {fxt.Test_parse_tmpl_str("{{#time:\\\\ Y|2012-01-02 03:04:05}}" , "\\ 2012");}
@Test public void Utc_escape_eos() {fxt.Test_parse_tmpl_str("{{#time:b\\|2012-01-02 03:04:05}}" , "b\\");}
@Test public void Utc_escape_newLine() {fxt.Test_parse_tmpl_str("{{#time:b\\\nb|2012-01-02 03:04:05}}" , "b\nb");}
@Test public void Utc_quote_basic() {fxt.Test_parse_tmpl_str("{{#time:b \"Y m d\" b|2012-01-02 03:04:05}}" , "b Y m d b");}
@Test public void Utc_quote_double() {fxt.Test_parse_tmpl_str("{{#time:b \"\" b|2012-01-02 03:04:05}}" , "b \" b");}
@Test public void Utc_quote_eos() {fxt.Test_parse_tmpl_str("{{#time:b \"|2012-01-02 03:04:05}}" , "b \"");}
@Test public void Utc_ws() {fxt.Test_parse_tmpl_str("{{#time: Y-m-d |2012-01-02 03:04:05}}" , "2012-01-02");}
@Test public void Lcl_date() {fxt.Test_parse_tmpl_str("{{#timel:Y-m-d|2012-01-02 03:04:05}}" , "2012-01-02");}
@Test public void Utc_dow_abrv() {fxt.Test_parse_tmpl_str("{{#time:D|20120301}}" , "Thu");}
@Test public void Utc_ymd() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|20120102}}" , "2012-01-02");}
@Test public void Utc_ym() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|201201}}" , "2012-01-01");}
@Test public void Utc_md() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|2-13}}" , "2012-02-13");} // PURPOSE.fix: m-d failed
@Test public void Slashes() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|2/13/12}}" , "2012-02-13");} // PURPOSE: assert slashes work
@Test public void Utc_day() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|March 27}}" , "2012-03-27");}
@Test public void Parse_day() {fxt.Test_parse_tmpl_str("{{#time:m d|March 27}}" , "03 27");}
@Test public void Month_name() {fxt.Test_parse_tmpl_str("{{#time:M|May 1 2012}}" , "May");}
@Test public void Time_before_date__dmy() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d H:i|04:50, 17 December 2010}}" , "2010-12-17 04:50");} // PAGE:en.w:Talk:Battle of Fort Washington
@Test public void Time_before_date__mdy() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d H:i|04:50, December 11, 2010}}" , "2010-12-11 04:50");} // PAGE:en.w:Wikipedia:WikiProject_Maine/members; DATE:2014-06-25
@Test public void Error() {fxt.Test_parse_tmpl_str("{{#time:M|2}}" , "<strong class=\"error\">Invalid year: 2</strong>");}
@Test public void Error2() {fxt.Test_parse_tmpl_str("{{#time:Y|July 28 - August 1, 1975}}" , "<strong class=\"error\">Invalid time</strong>");}
@Test public void Error3() {fxt.Test_parse_tmpl_str("{{#time:Y|106BC-43BC}}" , "<strong class=\"error\">Invalid time</strong>");}
@Test public void Timestamp() {fxt.Test_parse_tmpl_str("{{#time:F j, Y|20060827072854}}" , "August 27, 2006");} // PAGE:en.w:Great Fire of London
@Test public void Unixtime_read() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d h:i:s A|@0}}" , "1970-01-01 12:00:00 AM");} // EX:w:Wikipedia:WikiProject_Articles_for_creation/BLD_Preload
@Test public void Unixtime_read_neg() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d h:i:s A|@-3600}}" , "1969-12-31 11:00:00 PM");} // EX:w:Wikipedia:WikiProject_Articles_for_creation/October_-_November_2012_Backlog_Elimination_Drive; DATE:2014-05-10
@Test public void Unixtime_8_digit() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d h:i:s A|@20120304}}" , "1970-08-21 08:58:24 PM");} // PURPOSE: make sure yyyy-MM-dd is gobbled by "@" and not evaluated again as date; EX:w:Wikipedia:WikiProject_Articles_for_creation/October_-_November_2012_Backlog_Elimination_Drive; DATE:2014-05-10
@Test public void Unixtime_write() {fxt.Test_parse_tmpl_str("{{#time:U|2012-08-02}}" , "1343865600");} // PAGE:en.w:Opa (programming language)
@Test public void Year_4_digit() {fxt.Test_parse_tmpl_str("{{#time:Y|June 20, 451}}" , "0451");} // PAGE:en.w:Battle of the Catalaunian Plains
@Test public void Year_month() {fxt.Test_parse_tmpl_str("{{#time:F Y|November 2012}}" , "November 2012");} // PAGE:en.w:Project:Current events
@Test public void Day_addition_with_dash(){fxt.Test_parse_tmpl_str("{{#time:Y-m-d|2011-11-13 +1 day}}" , "2011-11-14");} // PURPOSE: +1 day was becoming -1 day b/c it was picking up - at -13; PAGE:en.w:Template:POTD/2012-10-09
@Test public void Hour_zero() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d H:i|August 18 2006 00:14}}" , "2006-08-18 00:14");} // PURPOSE: fix; invalid hour; PAGE:en.w:Talk:Martin Luther
@Test public void Iso() {fxt.Test_parse_tmpl_str("{{#time:c|2012-01-02 03:04:05}}" , "2012-01-02T03:04:05-05:00");}
@Test public void Ymdh() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|2012-01-02-99}}" , "2012-01-06");} // PURPOSE: "99" is treated as 99th hour; EX:w:LimeWire; DATE:2014-03-24
@Test public void Ymdh_noop() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|2012-01-02-100}}" , "2012-01-02");} // PURPOSE: "100" is ignored
@Test public void Month_is_0() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|2012-00-01}}" , "2011-12-01");} // PURPOSE: "0" for month is treated as -1; EX:w:Mariyinsky_Palace; DATE:2014-03-25
@Test public void Day_is_0() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|2012-12-00}}" , "2012-11-30");} // PURPOSE: "0" for day is treated as -1; EX:w:Mariyinsky_Palace; DATE:2014-03-25
@Test public void Day_suffix_y() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|11th Dec 2013}}" , "2013-12-11");} // PURPOSE: ignore suffix days; EX:11th; DATE:2014-03-25
@Test public void Day_suffix_n() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|32nd Dec 2013}}" , "<strong class=\"error\">Invalid day: 32</strong>");}
@Test public void Day_rel_today() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|today}}" , "2012-01-02");}
@Test public void Day_rel_tomorrow() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|tomorrow}}" , "2012-01-03");}
@Test public void Day_rel_yesterday() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|yesterday}}" , "2012-01-01");}
@Test public void Unit_rel_year_next() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|next year}}" , "2013-01-02");} // DATE:2014-05-02
@Test public void Unit_rel_year_last() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|last year}}" , "2011-01-02");}
@Test public void Unit_rel_year_previous(){fxt.Test_parse_tmpl_str("{{#time:Y-m-d|previous year}}" , "2011-01-02");}
@Test public void Unit_rel_year_this() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|this year}}" , "2012-01-02");}
@Test public void Time_rel_now() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d h:i:s A|now}}" , "2012-01-02 03:05:05 AM");} // NOTE: minute is 5, not 4, b/c each call to DateAdp_.Now() automatically increments by 1 minute; DATE:2014-04-13
@Test public void Empty_is_today() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|}}" , "2012-01-02");} // tested on MW
@Test public void Day_name_today() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|Monday}}" , "2012-01-02");} // 2012-01-02 is Monday, so return Monday; DATE:2014-05-02
@Test public void Day_name_future_1() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|Saturday}}" , "2012-01-07");} // return next Sunday; DATE:2014-05-02
@Test public void Day_name_future_2() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|Sunday}}" , "2012-01-08");} // return next Saturday; DATE:2014-05-02
@Test public void Day_name_dow() {fxt.Test_parse_tmpl_str("{{#time:w|Monday}}" , "1");}
@Test public void Timezone_offset() {
DateAdp.Timezone_offset_test = -18000;
fxt.Test_parse_tmpl_str("{{#time:Z|}}" , "-18000");
DateAdp.Timezone_offset_test = Int_.MinValue;
} // Z=timezone offset in seconds; http://php.net/manual/en/function.date.php;
@Test public void Timezone_plus() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d H:i:s|2012-01-02 03:04:05+06:30}}" , "2012-01-02 09:34:05");} // PURPOSE: handle timezone plus ; EX: +01:30; DATE:2014-08-26
@Test public void Timezone_minus() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d H:i:s|2012-01-02 09:34:05-06:30}}" , "2012-01-02 03:04:05");} // PURPOSE: handle timezone minus; EX: -01:30; DATE:2014-08-26
@Test public void Timezone_wrap() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d H:i:s|2012-01-31 22:30:05+01:30}}" , "2012-02-01 00:00:05");} // PURPOSE: handle timezone wrap ; DATE:2014-08-26
@Test public void Rfc5322() {fxt.Test_parse_tmpl_str("{{#time:r|}}" , "Mon, 02 Jan 2012 08:04:05 +0000");}
@Test public void Lang() {
Xol_lang fr_lang = fxt.App().Lang_mgr().Get_by_key_or_new(Bry_.new_a7("fr"));
Xol_msg_itm msg_itm = fr_lang.Msg_mgr().Itm_by_key_or_new(Bry_.new_a7("January"));
msg_itm.Atrs_set(Bry_.new_a7("Janvier"), false, false);
fxt.Test_parse_tmpl_str("{{#time:F|2012-01|fr}}" , "Janvier");
// fxt.Test_parse_tmpl_str("{{#time:F|2012-01|fr_bad}}" , "January"); // default to english // commented out; fails when running all at once
}
@Test public void Hour_with_dash() {fxt.Test_parse_tmpl_str("{{#time:c|January 2, 2001-06}}" , "2001-01-02T06:00:00-05:00");} // PURPOSE.fix: w:Vim_(text_editor) generates this during {{time ago|November 2, 1991-06-19|min_magnitude=days}}; DATE:2013-06-19
@Test public void Multiple_dates_gt_12() {fxt.Test_parse_tmpl_str("{{#time:c|January 2, 2001-06-19}}" , "2001-01-02T06:00:00-05:00");} // PURPOSE.fix: w:Vim_(text_editor)
@Test public void Multiple_dates_lt_12() {fxt.Test_parse_tmpl_str("{{#time:c|January 2, 2001-06-11}}" , "2001-01-02T06:00:00-05:00");} // PURPOSE.fix: w:Vim_(text_editor)
@Test public void Raw_H() {fxt.Test_parse_tmpl_str("{{#time:xnH}}" , "08");} // PURPOSE: ignore "xn" for now; chk 0-padded number is generated; DATE:2013-12-31
@Test public void Raw_h() {fxt.Test_parse_tmpl_str("{{#time:xnh}}" , "08");} // PURPOSE: ignore "xn" for now; chk 0-padded number is generated; DATE:2013-12-31
@Test public void Iso8601_T() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d h:i:s A|T1:23}}" , "2012-01-01 01:23:00 AM");} // handle "T" flag; PAGE:pl.w:StarCraft_II:_Wings_of_Liberty
@Test public void Iso8601_T_ws() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d h:i:s A|T 1:23}}" , "2012-01-01 01:23:00 AM");} // handle "T" flag and ws
@Test public void Iso8601_T_fail() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d h:i:s A|T2012-01-02}}" , "<strong class=\"error\">Invalid hour: T</strong>");} // handle "T" flag and ws
}

View File

@@ -0,0 +1,77 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
import org.junit.*;
public class Pft_func_time_foreign_tst {
@Before public void init() {fxt.Clear();} private Pft_func_time_foreign_fxt fxt = new Pft_func_time_foreign_fxt();
@After public void term() {fxt.Term();}
@Test public void Roman() {fxt.Test_parse("{{#time:xrY|2012}}" , "MMXII");}
@Test public void Thai() {fxt.Test_parse("{{#time:xkY|2012}}" , "2555");}
@Test public void Minguo() {fxt.Test_parse("{{#time:xoY|2012}}" , "101");}
@Test public void Hebrew_year_num() {fxt.Test_parse("{{#time:xjY|2012-01-02}}" , "5772");}
@Test public void Hebrew_month_num() {fxt.Test_parse("{{#time:xjn|2012-01-02}}" , "4");}
@Test public void Hebrew_day_num() {fxt.Test_parse("{{#time:xjj|2012-01-02}}" , "7");}
@Test public void Hebrew_month_days_count() {fxt.Test_parse("{{#time:xjt|2012-01-02}}" , "29");}
@Test public void Hebrew_month_name_full() {fxt.Init_msg("hebrew-calendar-m4" , "Tevet").Test_parse("{{#time:xjF|2012-01-02}}" , "Tevet");}
@Test public void Hebrew_month_name_gen() {fxt.Init_msg("hebrew-calendar-m4-gen" , "Tevet").Test_parse("{{#time:xjx|2012-01-02}}" , "Tevet");}
@Test public void Hebrew_numeral() {fxt.Test_parse("{{#time:xh}}" , "");}
@Test public void Hebrew_numeral_2() {fxt.Test_parse("{{#time:xhxjY|2014}}" , "ה'תשע\"ד");}
@Test public void Roman_various() {
fxt.Test_Roman( 1, "I");
fxt.Test_Roman( 2, "II");
fxt.Test_Roman( 3, "III");
fxt.Test_Roman( 4, "IV");
fxt.Test_Roman( 5, "V");
fxt.Test_Roman( 6, "VI");
fxt.Test_Roman( 7, "VII");
fxt.Test_Roman( 8, "VIII");
fxt.Test_Roman( 9, "IX");
fxt.Test_Roman( 10, "X");
fxt.Test_Roman( 11, "XI");
fxt.Test_Roman( 100, "C");
fxt.Test_Roman( 101, "CI");
fxt.Test_Roman( 111, "CXI");
fxt.Test_Roman(1000, "M");
fxt.Test_Roman(1001, "MI");
fxt.Test_Roman(4000, "4000");
}
}
class Pft_func_time_foreign_fxt {
private Xop_fxt fxt = new Xop_fxt();
public void Clear() {
fxt.Reset();
Tfds.Now_set(DateAdp_.new_(2012, 1, 2, 3, 4, 5, 6));
}
public void Term() {
Tfds.Now_enabled_n_();
}
public Pft_func_time_foreign_fxt Init_msg(String key, String val) {
Xol_msg_itm msg = fxt.Wiki().Msg_mgr().Get_or_make(Bry_.new_u8(key));
msg.Atrs_set(Bry_.new_u8(val), false, false);
return this;
}
public void Test_parse(String raw, String expd) {
fxt.Test_parse_tmpl_str_test(raw, "{{test}}", expd);
}
public void Test_Roman(int v, String expd) {
Bry_bfr bfr = Bry_bfr.new_(16);
Pfxtp_roman.ToRoman(v, bfr);
String actl = bfr.Xto_str_and_clear();
Tfds.Eq(expd, actl);
}
}

View File

@@ -0,0 +1,24 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
import org.junit.*;
public class Pft_func_time_int_tst {
@Before public void init() {fxt.Reset(); Tfds.Now_set(DateAdp_.new_(2012, 1, 2, 3, 4, 5, 6));} private Xop_fxt fxt = new Xop_fxt();
@Test public void Time_before_date__dmy() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d H:i|01:02 3.4.2005}}" , "2005-04-03 01:02");} // PAGE:sk.w:Dr._House; DATE:2014-09-23
@Test public void Time_before_date__mdy() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d H:i|01:02 3.14.2005}}" , "<strong class=\"error\">Invalid month: 14</strong>");} // mdy is invalid; DATE:2014-09-23
}

View File

@@ -0,0 +1,25 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
import org.junit.*;
public class Pft_func_time_uncommon_tst {
private Xop_fxt fxt = new Xop_fxt();
@Before public void init() {fxt.Reset(); Tfds.Now_set(DateAdp_.new_(2012, 1, 2, 3, 4, 5, 6));}
@After public void term() {Tfds.Now_enabled_n_();}
@Test public void Year_5_digits() {fxt.Test_parse_tmpl_str_test("{{#time:Y-m-d|00123-4-5}}" , "{{test}}" , "2003-04-05");} // PURPOSE: emulate PHP's incorrect date parsing; EX:ca.w:Nicolau_de_Mira; DATE:2014-04-17
}

View File

@@ -0,0 +1,209 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
class Pxd_eval_year {
public static void Eval_at_pos_0(Pxd_parser tctx, Pxd_itm_int cur) {
Pxd_itm[] data_ary = tctx.Data_ary();
if (tctx.Data_ary_len() < 2) return;
Pxd_itm_int itm_1 = Pxd_itm_int_.CastOrNull(data_ary[1]);
if (itm_1 != null) {
if (!Pxd_eval_seg.Eval_as_m(tctx, itm_1)) return;
}
if (tctx.Data_ary_len() < 3) return;
Pxd_itm_int itm_2 = Pxd_itm_int_.CastOrNull(data_ary[2]);
if (itm_2 != null) {
if (!Pxd_eval_seg.Eval_as_d(tctx, itm_2)) return;
}
if (tctx.Data_ary_len() == 4) { // handle strange constructions like 2014-03-24-25;
Pxd_itm_int itm_3 = Pxd_itm_int_.CastOrNull(data_ary[3]);
if (itm_3 != null) { // treat 4th number as hour adjustment; EX: 2014-03-24-72 -> 2014-03-26; DATE:2014-03-24
int itm_3_val = itm_3.Val();
if (itm_3_val > 99) itm_3_val = 0; // only adjust if number is between 0 and 99;
Pxd_itm_int_.Convert_to_rel(tctx, itm_3, Pxd_parser_.Unit_name_hour, DateAdp_.SegIdx_hour, itm_3_val);
}
}
}
public static void Eval_at_pos_2(Pxd_parser tctx, Pxd_itm_int cur) {
Pxd_itm[] data_ary = tctx.Data_ary();
Pxd_itm_int itm_0 = Pxd_itm_int_.CastOrNull(data_ary[0]);
Pxd_itm_int itm_1 = Pxd_itm_int_.CastOrNull(data_ary[1]);
if (itm_0 == null || itm_1 == null) return; // 0 or 1 is not an int;
if (itm_1.Val() > 13) {
if (!Pxd_eval_seg.Eval_as_m(tctx, itm_0)) return;
if (!Pxd_eval_seg.Eval_as_d(tctx, itm_1)) return;
}
else {
if (!Pxd_eval_seg.Eval_as_d(tctx, itm_0)) return;
if (!Pxd_eval_seg.Eval_as_m(tctx, itm_1)) return;
}
}
public static void Eval_at_pos_n(Pxd_parser tctx, Pxd_itm_int cur) { // where n > 2; EX: 1:23 4.5.2010; PAGE:sk.w:Dr._House; DATE:2014-09-23
Pxd_itm[] data_ary = tctx.Data_ary(); int data_ary_len = data_ary.length; int data_idx = cur.Data_idx();
Pxd_itm_int lhs_1 = Pxd_itm_int_.Get_int_bwd(data_ary, data_ary_len, data_idx - 1);
if (lhs_1 != null) { // lhs_1 is int; EX:05-2014
Pxd_itm_int lhs_0 = Pxd_itm_int_.Get_int_bwd(data_ary, data_ary_len, data_idx - 2);
if (lhs_0 != null) { // lhs_0 is int; EX:01-05-2014
if (!Pxd_eval_seg.Eval_as_d(tctx, lhs_0)) return;
if (!Pxd_eval_seg.Eval_as_m(tctx, lhs_1)) return;
if (!Pxd_eval_seg.Eval_as_y(tctx, cur )) return;
}
}
}
public static final int Month_max = 12;
}
class Pxd_eval_seg {
public static boolean Eval_as_y(Pxd_parser tctx, Pxd_itm_int itm) {
int val = itm.Val();
switch (itm.Digits()) {
case 1:
case 2:
itm.Val_(val + (val > 69 ? 1900 : 2000)); // assume that 70 refers to 1970 and 69 refers to 2069
tctx.Seg_idxs_(itm, DateAdp_.SegIdx_year);
return true;
case 3: // NOTE: 3 digit numbers are valid years; MW relies on PHP time parse which always zero-pad numbers; PAGE:en.w:Battle of the Catalaunian Plains; {{#time:Y|June 20, 451}}
case 4:
tctx.Seg_idxs_(itm, DateAdp_.SegIdx_year);
return true;
}
tctx.Err_set(Pft_func_time_log.Invalid_year, Bry_fmtr_arg_.int_(val));
return false;
}
public static boolean Eval_as_m(Pxd_parser tctx, Pxd_itm_int itm) {
int val = itm.Val();
switch (itm.Digits()) {
case 1:
case 2:
if (val > 0 && val < 13) {
tctx.Seg_idxs_(itm, DateAdp_.SegIdx_month);
return true;
}
else if (val == 0) {// 0 day means subtract 1; EX:w:Mariyinsky_Palace; DATE:2014-03-25
Pxd_itm_int_.Convert_to_rel(tctx, itm, Pxd_parser_.Unit_name_month, DateAdp_.SegIdx_month, -1);
return true;
}
break;
}
tctx.Err_set(Pft_func_time_log.Invalid_month, Bry_fmtr_arg_.int_(val));
return false;
}
public static boolean Eval_as_d(Pxd_parser tctx, Pxd_itm_int itm) {
int val = itm.Val();
switch (itm.Digits()) {
case 1:
case 2:
if (val > 0 && val < 32) {
tctx.Seg_idxs_(itm, DateAdp_.SegIdx_day);
return true;
}
else if (val == 0) { // 0 day means subtract 1; EX:w:Mariyinsky_Palace; DATE:2014-03-25
Pxd_itm_int_.Convert_to_rel(tctx, itm, Pxd_parser_.Unit_name_day, DateAdp_.SegIdx_day, -1);
return true;
}
break;
}
tctx.Err_set(Pft_func_time_log.Invalid_day, Bry_fmtr_arg_.int_(val));
return false;
}
public static boolean Eval_as_h(Pxd_parser tctx, Pxd_itm_int itm) {
int val = itm.Val();
switch (itm.Digits()) {
case 1:
case 2:
if (val > -1 && val < 25) {
tctx.Seg_idxs_(itm, DateAdp_.SegIdx_hour, val);
return true;
}
break;
}
tctx.Err_set(Pft_func_time_log.Invalid_hour, Bry_fmtr_arg_.int_(val));
return false;
}
public static boolean Eval_as_n(Pxd_parser tctx, Pxd_itm_int itm) {
int val = itm.Val();
switch (itm.Digits()) {
case 1:
case 2:
if (val > -1 && val < 60) {
tctx.Seg_idxs_(itm, DateAdp_.SegIdx_minute, val);
return true;
}
break;
}
tctx.Err_set(Pft_func_time_log.Invalid_minute, Bry_fmtr_arg_.int_(val));
return false;
}
public static boolean Eval_as_s(Pxd_parser tctx, Pxd_itm_int itm) {
int val = itm.Val();
switch (itm.Digits()) {
case 1:
case 2:
if (val > -1 && val < 60) {
tctx.Seg_idxs_(itm, DateAdp_.SegIdx_second);
return true;
}
break;
}
tctx.Err_set(Pft_func_time_log.Invalid_second, Bry_fmtr_arg_.int_(val));
return false;
}
public static boolean Eval_as_tz_h(Pxd_parser tctx, Pxd_itm_int itm, boolean negative) {
if (negative) itm.Val_(itm.Val() * -1);
int val = itm.Val();
switch (itm.Digits()) {
case 1:
case 2:
if (val > -12 && val < 12) {
itm.Val_is_adj_(Bool_.Y);
itm.Seg_idx_(DateAdp_.SegIdx_hour);
return true;
}
break;
}
tctx.Err_set(Pft_func_time_log.Invalid_hour, Bry_fmtr_arg_.int_(val));
return false;
}
public static boolean Eval_as_tz_m(Pxd_parser tctx, Pxd_itm_int itm, boolean negative) {
int val = itm.Val();
if (negative) val *= -1;
switch (itm.Digits()) {
case 1:
case 2:
if (val > -60 && val < 60) {
itm.Val_is_adj_(Bool_.Y);
itm.Seg_idx_(DateAdp_.SegIdx_minute);
return true;
}
break;
}
tctx.Err_set(Pft_func_time_log.Invalid_minute, Bry_fmtr_arg_.int_(val));
return false;
}
public static byte Eval_as_tz_sym(Pxd_parser tctx, Pxd_itm[] tkns, Pxd_itm_int hour_itm) {
Pxd_itm sym = Pxd_itm_.Find_bwd__non_ws(tkns, hour_itm.Ary_idx());
switch (sym.Tkn_tid()) {
case Pxd_itm_.Tid_sym:
Pxd_itm_sym sym_itm = (Pxd_itm_sym)sym;
if (sym_itm.Sym_byte() == Byte_ascii.Plus)
return Bool_.Y_byte;
break;
case Pxd_itm_.Tid_dash: return Bool_.N_byte;
}
tctx.Err_set(Pft_func_time_log.Invalid_timezone, Bry_fmtr_arg_.bry_("null"));
return Bool_.__byte;
}
}

View File

@@ -0,0 +1,122 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
interface Pxd_itm {
byte Tkn_tid();
int Ary_idx();
int Seg_idx();
int Eval_idx();
int Data_idx(); void Data_idx_(int v);
void Eval(Pxd_parser state);
void Time_ini(DateAdpBldr bldr);
}
class Pxd_itm_ {
public static final int
Tid_null = 0
, Tid_int = 1
, Tid_int_dmy_14 = 2
, Tid_int_hms_6 = 3
, Tid_month_name = 4
, Tid_dow_name = 5
, Tid_unit = 6
, Tid_ago = 7
, Tid_day_suffix = 8 // 1st, 2nd
, Tid_day_relative = 9 // today, tomorrow, yesterday
, Tid_time_relative = 10 // now
, Tid_unit_relative = 11 // next, previous
, Tid_unixtime = 12 // @123
, Tid_iso8601_t = 13 // T
, Tid_dash = Byte_ascii.Dash
, Tid_dot = Byte_ascii.Dot
, Tid_slash = Byte_ascii.Slash
, Tid_colon = Byte_ascii.Colon
, Tid_ws = 98
, Tid_sym = 99
;
public static Pxd_itm Find_bwd__non_ws(Pxd_itm[] tkns, int bgn) {
for (int i = bgn - 1; i > -1; --i) {
Pxd_itm itm = tkns[i];
if (itm.Tkn_tid() != Tid_ws) return itm;
}
return null;
}
public static Pxd_itm Find_fwd_by_tid(Pxd_itm[] tkns, int bgn, int tid) {
int len = tkns.length;
for (int i = bgn; i < len; i++) {
Pxd_itm itm = tkns[i];
if (tid == itm.Tkn_tid()) return itm;
}
return null;
}
public static boolean Eval_needed(Pxd_itm itm) {return itm.Seg_idx() == -1;}
}
abstract class Pxd_itm_base implements Pxd_itm {
public abstract byte Tkn_tid();
public int Ary_idx() {return ary_idx;} private int ary_idx;
public int Seg_idx() {return seg_idx;} private int seg_idx = Seg_idx_null;
public void Seg_idx_(int v) {seg_idx = v;}
public int Data_idx() {return data_idx;} public void Data_idx_(int v) {data_idx = v;} private int data_idx;
public abstract int Eval_idx();
@gplx.Virtual public void Eval(Pxd_parser state) {}
@gplx.Virtual public void Time_ini(DateAdpBldr bldr) {}
public void Ctor(int ary_idx) {this.ary_idx = ary_idx;}
public static final int Seg_idx_null = -1, Seg_idx_skip = -2;
}
interface Pxd_itm_prototype {
Pxd_itm MakeNew(int ary_idx);
}
class DateAdpBldr {
public DateAdp Date() {
if (dirty) {
if (date == null) date = DateAdp_.seg_(seg_ary); // date not set and seg_ary is dirty; make date = seg_ary;
return date;
}
else
return DateAdp_.Now(); // not dirtied; default to now;
}
public DateAdpBldr Date_(DateAdp v) {date = v; return this;} DateAdp date = null;
public DateAdpBldr Seg_set(int idx, int val) {
if (date == null) seg_ary[idx] = val;
else {
seg_ary = date.XtoSegAry();
seg_ary[idx] = val;
date = DateAdp_.seg_(seg_ary);
}
dirty = true;
return this;
}
public DateAdp Bld() {
return date == null ? DateAdp_.seg_(seg_ary) : date;
}
public DateAdpBldr(int... seg_ary) {this.seg_ary = seg_ary;}
int[] seg_ary = new int[DateAdp_.SegIdx__max]; boolean dirty = false;
}
class Pft_func_time_log {
private static final Gfo_msg_grp owner = Gfo_msg_grp_.new_(Xoa_app_.Nde, "time_parser");
public static final Gfo_msg_itm
Invalid_day = Gfo_msg_itm_.new_warn_(owner, "Invalid day: ~{0}")
, Invalid_month = Gfo_msg_itm_.new_warn_(owner, "Invalid month: ~{0}")
, Invalid_year = Gfo_msg_itm_.new_warn_(owner, "Invalid year: ~{0}")
, Invalid_year_mid = Gfo_msg_itm_.new_warn_(owner, "Invalid date: 4 digit year must be either yyyy-##-## or ##-##-yyyy")
, Invalid_hour = Gfo_msg_itm_.new_warn_(owner, "Invalid hour: ~{0}")
, Invalid_minute = Gfo_msg_itm_.new_warn_(owner, "Invalid minute: ~{0}")
, Invalid_second = Gfo_msg_itm_.new_warn_(owner, "Invalid second: ~{0}")
, Invalid_date = Gfo_msg_itm_.new_warn_(owner, "Invalid date: ~{0}")
, Invalid_timezone = Gfo_msg_itm_.new_warn_(owner, "Invalid timezone: ~{0}")
;
}

View File

@@ -0,0 +1,299 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
interface Pxd_itm_int_interface extends Pxd_itm {
int Xto_int_or(int or);
}
class Pxd_itm_int extends Pxd_itm_base implements Pxd_itm_int_interface {
public Pxd_itm_int(int ary_idx, int digits, int val) {
this.Ctor(ary_idx); this.digits = digits; this.val = val;
switch (digits) {
case 4: // assume year
eval_idx = 50;
break;
case 2:
case 1:
default:
if (val > 12) // either day or year; not month
eval_idx = 60;
else
eval_idx = 70; // day, year, or month
break;
}
}
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_int;}
@Override public int Eval_idx() {return eval_idx;} private int eval_idx = 99;
public int Val() {return val;} public Pxd_itm_int Val_(int v) {val = v; return this;} private int val;
public boolean Val_is_adj() {return val_is_adj;} public void Val_is_adj_(boolean v) {val_is_adj = v;} private boolean val_is_adj;
public int Xto_int_or(int or) {return val;}
public int Digits() {return digits;} private int digits;
@Override public void Time_ini(DateAdpBldr bldr) {
int seg_idx = this.Seg_idx();
if (seg_idx == Pxd_itm_base.Seg_idx_skip) return;
if (val_is_adj) {
if (val == 0) return; // no adjustment to make
DateAdp date = bldr.Date();
switch (seg_idx) {
case DateAdp_.SegIdx_hour: date = date.Add_hour(val); break;
case DateAdp_.SegIdx_minute: date = date.Add_minute(val); break;
default: return;
}
bldr.Date_(date);
}
else
bldr.Seg_set(seg_idx, val);
}
@Override public void Eval(Pxd_parser tctx) {
int data_idx = this.Data_idx();
if (this.Seg_idx() != Pxd_itm_base.Seg_idx_null) return; // has seg_idx; already eval'd by something else
switch (digits) {
case 5: // 5 digits
switch (data_idx) {
case 0: Pxd_eval_year.Eval_at_pos_0(tctx, this); break; // year at pos 0; EX: 01234-02-03
case 1: tctx.Err_set(Pft_func_time_log.Invalid_date); return; // year at pos 1; invalid; EX: 01-01234-02
case 2: tctx.Err_set(Pft_func_time_log.Invalid_date); break; // year at pos 2; invalid; EX: 01-02-01234
}
val = 2000 + (val % 10); // NOTE: emulate PHP's incorrect behavior with 5 digit years; EX:ca.w:Nicolau_de_Mira; DATE:2014-04-18
tctx.Seg_idxs_(this, DateAdp_.SegIdx_year);
break;
case 4: // 4 digits; assume year
switch (data_idx) {
case 0: Pxd_eval_year.Eval_at_pos_0(tctx, this); break; // year at pos 0; EX: 2001-02-03
case 1: tctx.Err_set(Pft_func_time_log.Invalid_year_mid); return;// year at pos 1; invalid; EX: 02-2003-03
case 2: Pxd_eval_year.Eval_at_pos_2(tctx, this); break; // year at pos 2; EX: 02-03-2001
default: Pxd_eval_year.Eval_at_pos_n(tctx, this); break; // year at pos n; EX: 04:05 02-03-2001
}
tctx.Seg_idxs_(this, DateAdp_.SegIdx_year);
break;
default:
Pxd_itm[] data_ary = tctx.Data_ary();
int data_ary_len = data_ary.length;
Pxd_itm_int cur_itm = Pxd_itm_int_.CastOrNull(data_ary[data_idx]);
Pxd_itm lhs_itm = data_idx == 0 ? null : data_ary[data_idx - 1];
Pxd_itm rhs_itm = data_idx == data_ary_len - 1 ? null : data_ary[data_idx + 1];
if ( lhs_itm != null && lhs_itm.Seg_idx() == DateAdp_.SegIdx_month // itm on left is month
&& rhs_itm != null && rhs_itm.Seg_idx() == DateAdp_.SegIdx_year // itm on right is year
&& tctx.Seg_idxs()[DateAdp_.SegIdx_day] == -1 // day not yet set; needed for {{#time:Y|July 28 - August 1, 1975}}
)
if (!Pxd_eval_seg.Eval_as_d(tctx, cur_itm)) return; // cur int should be day; EX:January 1, 2010; PAGE:en.w:Wikipedia:WikiProject_Maine/members; DATE:2014-06-25
if (val > Month_max) { // value is not a month; assume day; DATE:2013-03-15
switch (data_idx) {
case 0: // > 12 in slot 0
if (Match_sym(tctx, Bool_.Y, Pxd_itm_.Tid_dot)) // next sym is dot; assume m.d.y; EX: 22.5.70
Eval_day_at_pos_0(tctx);
else // next sym is not dot; assume y-m-d; EX: 70-5-22
Eval_month_at_pos_0(tctx);
break;
case 1: Eval_month_at_pos_1(tctx); break; // > 12 in slot 1; assume m.d; EX: 5.22
case 2: // > 12 in slot 2
if (Match_sym(tctx, Bool_.N, Pxd_itm_.Tid_dot)) // prv sym is dot; assume d.m.y; EX: 22.5.70
Eval_dmy_at_y(tctx);
else // prv sym is not dot; assume m-d-y; EX: 22.5.70
Eval_month_at_pos_2(tctx);
break;
case 4:
Eval_unknown_at_pos_4(tctx);
break;
}
}
else { // value is either day or month;
switch (data_idx) {
case 0: Eval_unknown_at_pos_0(tctx); break;
case 3: Eval_unknown_at_pos_3(tctx); break;
case 4: Eval_unknown_at_pos_4(tctx); break;
}
}
break;
}
}
public static final int Month_max = 12;
private void Eval_unknown_at_pos_3(Pxd_parser tctx) { // int at pos 4
if ( tctx.Seg_idxs_chk(DateAdp_.SegIdx_year, DateAdp_.SegIdx_month, DateAdp_.SegIdx_day) // check that ymd is set
&& Match_sym(tctx, false, Pxd_itm_.Tid_dash)) // check that preceding symbol is "-"
Pxd_eval_seg.Eval_as_h(tctx, this); // mark as hour; handles strange fmts like November 2, 1991-06; DATE:2013-06-19
}
private void Eval_unknown_at_pos_4(Pxd_parser tctx) {
if ( tctx.Seg_idxs_chk(DateAdp_.SegIdx_year
, DateAdp_.SegIdx_month, DateAdp_.SegIdx_day, DateAdp_.SegIdx_hour) // check that ymdh is set
&& Match_sym(tctx, false, Pxd_itm_.Tid_dash)) // check that preceding symbol is "-"
tctx.Seg_idxs_(this, Pxd_itm_base.Seg_idx_skip); // mark as ignore; handles strange fmts like November 2, 1991-06-19; DATE:2013-06-19
}
boolean Match_sym(Pxd_parser tctx, boolean fwd, int sym_tid) {
int sym_idx = this.Ary_idx() + (fwd ? 1 : -1);
Pxd_itm[] sym_tkns = tctx.Tkns();
if (sym_idx < 0 || sym_idx > sym_tkns.length) return false; // NOTE: was Data_ary_len; DATE:2013-06-19
return sym_tkns[sym_idx].Tkn_tid() == sym_tid;
}
private void Eval_month_at_pos_0(Pxd_parser tctx) {
Pxd_itm[] data_ary = tctx.Data_ary();
if (tctx.Data_ary_len() < 2) return;
Pxd_itm_int itm_1 = Pxd_itm_int_.CastOrNull(data_ary[1]);
if (itm_1 != null) {
if (!Pxd_eval_seg.Eval_as_m(tctx, itm_1)) return;
}
if (tctx.Data_ary_len() > 2) {
Pxd_itm_int itm_2 = Pxd_itm_int_.CastOrNull(data_ary[2]);
if (itm_2 != null) {
if (!Pxd_eval_seg.Eval_as_d(tctx, itm_2)) return;
}
}
Pxd_eval_seg.Eval_as_y(tctx, this);
}
private void Eval_day_at_pos_0(Pxd_parser tctx) { // eval 1 as month; 2 as year, 0 as day
Pxd_itm[] data_ary = tctx.Data_ary();
if (tctx.Data_ary_len() < 2) return;
Pxd_itm_int itm_1 = Pxd_itm_int_.CastOrNull(data_ary[1]);
if (itm_1 != null) {
if (!Pxd_eval_seg.Eval_as_m(tctx, itm_1)) return;
}
if (tctx.Data_ary_len() > 2) {
Pxd_itm_int itm_2 = Pxd_itm_int_.CastOrNull(data_ary[2]);
if (itm_2 != null) {
if (!Pxd_eval_seg.Eval_as_y(tctx, itm_2)) return;
}
}
Pxd_eval_seg.Eval_as_d(tctx, this);
}
private void Eval_dmy_at_y(Pxd_parser tctx) { // dmy format; cur is y (slot 2)
Pxd_itm[] data_ary = tctx.Data_ary();
if (tctx.Data_ary_len() < 3) return; // since proc starts at y, assume at least d-m-y (not m-y)
Pxd_itm_int itm_1 = Pxd_itm_int_.CastOrNull(data_ary[1]);
if (itm_1 != null) {
if (!Pxd_eval_seg.Eval_as_m(tctx, itm_1)) return;
}
Pxd_itm_int itm_0 = Pxd_itm_int_.CastOrNull(data_ary[0]);
if (itm_0 != null) {
if (!Pxd_eval_seg.Eval_as_y(tctx, itm_0)) return;
}
Pxd_eval_seg.Eval_as_y(tctx, this);
}
private void Eval_month_at_pos_1(Pxd_parser tctx) {
Pxd_itm[] data_ary = tctx.Data_ary();
Pxd_itm_int itm_0 = Pxd_itm_int_.CastOrNull(data_ary[0]);
if (itm_0 != null) {
if (!Pxd_eval_seg.Eval_as_m(tctx, itm_0)) return;
}
if (tctx.Data_ary_len() > 2) {
Pxd_itm_int itm_2 = Pxd_itm_int_.CastOrNull(data_ary[2]);
if (itm_2 != null) {
if (!Pxd_eval_seg.Eval_as_y(tctx, itm_2)) return;
}
}
Pxd_eval_seg.Eval_as_d(tctx, this);
}
private void Eval_month_at_pos_2(Pxd_parser tctx) {
Pxd_itm[] data_ary = tctx.Data_ary();
Pxd_itm_int itm_0 = Pxd_itm_int_.CastOrNull(data_ary[0]);
if (itm_0 != null) {
if (!Pxd_eval_seg.Eval_as_m(tctx, itm_0)) return;
}
Pxd_itm_int itm_1 = Pxd_itm_int_.CastOrNull(data_ary[1]);
if (itm_1 != null) {
if (!Pxd_eval_seg.Eval_as_d(tctx, itm_1)) return;
}
Pxd_eval_seg.Eval_as_y(tctx, this);
}
private void Eval_unknown_at_pos_0(Pxd_parser tctx) { // NOTE: assumes dmy format
Pxd_itm[] data_ary = tctx.Data_ary();
if (tctx.Data_ary_len() < 2) {tctx.Err_set(Pft_func_time_log.Invalid_year, Bry_fmtr_arg_.int_(val)); return;}
Pxd_itm_int itm_1 = Pxd_itm_int_.CastOrNull(data_ary[1]);
if (itm_1 != null) { // if 1st itm to right is number, parse it as month
if (!Pxd_eval_seg.Eval_as_m(tctx, itm_1)) return;
}
if (tctx.Data_ary_len() > 2) {
Pxd_itm_int itm_2 = Pxd_itm_int_.CastOrNull(data_ary[2]);
if (itm_2 != null) { // if 2nd itm to right is number, assume it as year
if (!Pxd_eval_seg.Eval_as_y(tctx, itm_2)) return;
}
}
Pxd_eval_seg.Eval_as_d(tctx, this); // parse current as day (dmy format)
}
}
class Pxd_itm_int_ {
public static void Convert_to_rel(Pxd_parser tctx, Pxd_itm_int itm, byte[] unit_name, int seg_idx, int rel_val) {
int tkn_idx = itm.Ary_idx();
tctx.Tkns()[tkn_idx] = new Pxd_itm_unit(tkn_idx, unit_name, seg_idx, rel_val);
}
public static Pxd_itm_int CastOrNull(Pxd_itm itm) {return itm.Tkn_tid() == Pxd_itm_.Tid_int ? (Pxd_itm_int)itm : null; }
public static Pxd_itm_int GetNearest(Pxd_itm[] tkns, int tkn_idx, boolean fwd) {
int adj = 1, end = tkns.length;
if (!fwd) {
adj = -1;
end = -1;
}
for (int i = tkn_idx + adj; i != end; i += adj) {
Pxd_itm itm = tkns[i];
if (itm.Tkn_tid() == Pxd_itm_.Tid_int) {
Pxd_itm_int itm_int = (Pxd_itm_int)itm;
return itm_int.Seg_idx() == -1 ? itm_int : null;
}
}
return null;
}
public static int Read_nearest_as_int_and_skip(Pxd_parser tctx, Pxd_itm[] tkns, int bgn, boolean fwd, int or) {
int adj = 1, end = tkns.length;
if (!fwd) {
adj = -1;
end = -1;
}
Pxd_itm dash_itm = null;
for (int i = bgn + adj; i != end; i += adj) {
Pxd_itm itm = tkns[i];
switch (itm.Tkn_tid()) {
case Pxd_itm_.Tid_dash:
dash_itm = itm; // TODO: throw error if "--"; {{#time:U|@--1}}
break;
case Pxd_itm_.Tid_int:
case Pxd_itm_.Tid_int_dmy_14:
case Pxd_itm_.Tid_int_hms_6:
Pxd_itm_int_interface itm_int = (Pxd_itm_int_interface)itm;
int itm_int_seg_idx = itm_int.Seg_idx();
if (itm_int_seg_idx == -1) { // not evaluated
int factor = 1;
if (dash_itm != null) {
tctx.Seg_idxs_((Pxd_itm_base)dash_itm, Pxd_itm_base.Seg_idx_skip, -1);
factor = -1;
}
tctx.Seg_idxs_((Pxd_itm_base)itm, Pxd_itm_base.Seg_idx_skip, -1);
return itm_int.Xto_int_or(or) * factor;
}
break;
}
}
return or;
}
public static Pxd_itm_int Get_int_bwd(Pxd_itm[] data_ary, int data_ary_len, int idx) {
if (idx > -1) { // make sure idx is > 0
Pxd_itm rv = data_ary[idx]; // assume caller not passing in anything > ary.len
if ( rv.Tkn_tid() == Pxd_itm_.Tid_int // rv is int
&& Pxd_itm_.Eval_needed(rv) // rv needs evaluation
)
return (Pxd_itm_int)rv; // return it
}
return null;
}
public static Pxd_itm Get_int_fwd(Pxd_itm[] data_ary, int data_ary_len, int idx) {
if (idx < data_ary_len) {
Pxd_itm rv = data_ary[idx];
if ( rv.Tkn_tid() == Pxd_itm_.Tid_int
&& rv.Seg_idx() == -1)
return rv;
}
return null;
}
}

View File

@@ -0,0 +1,134 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
class Pxd_itm_colon extends Pxd_itm_base {
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_colon;}
@Override public int Eval_idx() {return 20;}
@Override public void Eval(Pxd_parser state) {
int colon_count = ++state.Colon_count;
Pxd_itm[] tkns = state.Tkns();
Pxd_itm_int itm_int = null;
switch (colon_count) {
case 1: // hh:mm
itm_int = Pxd_itm_int_.GetNearest(tkns, this.Ary_idx(), Bool_.N);
if (itm_int == null) {state.Err_set(Pft_func_time_log.Invalid_hour, Bry_fmtr_arg_.bry_("null")); return;}
if (!Pxd_eval_seg.Eval_as_h(state, itm_int)) return;
itm_int = Pxd_itm_int_.GetNearest(tkns, this.Ary_idx(), true);
if (!Pxd_eval_seg.Eval_as_n(state, itm_int)) return;
break;
case 2: // :ss
itm_int = Pxd_itm_int_.GetNearest(tkns, this.Ary_idx(), true);
if (!Pxd_eval_seg.Eval_as_s(state, itm_int)) return;
break;
case 3: // +hh:mm; DATE:2014-08-26
itm_int = Pxd_itm_int_.GetNearest(tkns, this.Ary_idx(), Bool_.N);
if (itm_int == null) {state.Err_set(Pft_func_time_log.Invalid_timezone, Bry_fmtr_arg_.bry_("null")); return;}
byte tz_positive_val = Pxd_eval_seg.Eval_as_tz_sym(state, tkns, itm_int);
if (tz_positive_val == Bool_.__byte) return;
boolean tz_negative = tz_positive_val == Bool_.N_byte;
if (!Pxd_eval_seg.Eval_as_tz_h(state, itm_int, tz_negative)) return;
itm_int = Pxd_itm_int_.GetNearest(tkns, this.Ary_idx(), Bool_.Y);
if (itm_int == null) {state.Err_set(Pft_func_time_log.Invalid_timezone, Bry_fmtr_arg_.bry_("null")); return;}
if (tz_negative) itm_int.Val_(itm_int.Val() * -1);
if (!Pxd_eval_seg.Eval_as_tz_m(state, itm_int, tz_negative)) return;
break;
}
}
public Pxd_itm_colon(int ary_idx) {this.Ctor(ary_idx);}
}
class Pxd_itm_null extends Pxd_itm_base {
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_null;}
@Override public int Eval_idx() {return 99;}
public static final Pxd_itm_null _ = new Pxd_itm_null();
}
class Pxd_itm_dash extends Pxd_itm_base {
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_dash;}
@Override public int Eval_idx() {return 99;}
public Pxd_itm_dash(int ary_idx) {this.Ctor(ary_idx);}
}
class Pxd_itm_dot extends Pxd_itm_base {
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_dot;}
@Override public int Eval_idx() {return 99;}
public Pxd_itm_dot(int ary_idx) {this.Ctor(ary_idx);}
}
class Pxd_itm_ws extends Pxd_itm_base {
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_ws;}
@Override public int Eval_idx() {return 99;}
public Pxd_itm_ws(int ary_idx) {this.Ctor(ary_idx);}
}
class Pxd_itm_slash extends Pxd_itm_base {
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_slash;}
@Override public int Eval_idx() {return 99;}
public Pxd_itm_slash(int ary_idx) {this.Ctor(ary_idx);}
}
class Pxd_itm_sym extends Pxd_itm_base {
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_sym;}
@Override public int Eval_idx() {return 99;}
@Override public void Time_ini(DateAdpBldr bldr) {}
public byte Sym_byte() {return sym_byte;} private byte sym_byte;
public Pxd_itm_sym(int ary_idx, byte val) {this.Ctor(ary_idx); this.sym_byte = val;}
}
class Pxd_itm_int_dmy_14 extends Pxd_itm_base implements Pxd_itm_int_interface {
public Pxd_itm_int_dmy_14(int ary_idx, byte[] src, int digits) {this.Ctor(ary_idx); this.src = src; this.digits = digits;} private byte[] src; int digits;
public int Xto_int_or(int or) {return Bry_.Xto_int_or(src, or);}
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_int_dmy_14;}
@Override public int Eval_idx() {return eval_idx;} private int eval_idx = 20;
@Override public void Time_ini(DateAdpBldr bldr) {
if (this.Seg_idx() != Pxd_itm_base.Seg_idx_null) return; // has seg_idx; already eval'd by something else
bldr.Seg_set(DateAdp_.SegIdx_year , Bry_.Xto_int_or(src, 0, 4, 0));
bldr.Seg_set(DateAdp_.SegIdx_month , Bry_.Xto_int_or(src, 4, 6, 0));
if (digits > 6) {
bldr.Seg_set(DateAdp_.SegIdx_day , Bry_.Xto_int_or(src, 6, 8, 0));
if (digits > 8) {
bldr.Seg_set(DateAdp_.SegIdx_hour , Bry_.Xto_int_or(src, 8, 10, 0));
if (digits > 10) {
bldr.Seg_set(DateAdp_.SegIdx_minute , Bry_.Xto_int_or(src, 10, 12, 0));
if (digits > 12)
bldr.Seg_set(DateAdp_.SegIdx_second , Bry_.Xto_int_or(src, 12, 14, 0));
}
}
}
}
}
class Pxd_itm_int_mhs_6 extends Pxd_itm_base implements Pxd_itm_int_interface {
public Pxd_itm_int_mhs_6(int ary_idx, byte[] src) {this.Ctor(ary_idx); this.src = src;} private byte[] src;
public int Xto_int_or(int or) {return Bry_.Xto_int_or(src, or);}
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_int_hms_6;}
@Override public int Eval_idx() {return eval_idx;} private int eval_idx = 20;
@Override public void Time_ini(DateAdpBldr bldr) {
if (this.Seg_idx() != Pxd_itm_base.Seg_idx_null) return; // has seg_idx; already eval'd by something else
bldr.Seg_set(DateAdp_.SegIdx_hour , Bry_.Xto_int_or(src, 0, 2, 0));
bldr.Seg_set(DateAdp_.SegIdx_minute , Bry_.Xto_int_or(src, 2, 4, 0));
bldr.Seg_set(DateAdp_.SegIdx_second , Bry_.Xto_int_or(src, 4, 6, 0));
}
}
class Pxd_itm_sorter implements gplx.lists.ComparerAble {
public int compare(Object lhsObj, Object rhsObj) {
Pxd_itm lhs = (Pxd_itm)lhsObj;
Pxd_itm rhs = (Pxd_itm)rhsObj;
return Int_.Compare(lhs.Eval_idx(), rhs.Eval_idx());
}
public static final Pxd_itm_sorter _ = new Pxd_itm_sorter();
public static Pxd_itm[] XtoAryAndSort(Pxd_itm[] src, int src_len) {
Pxd_itm[] rv = new Pxd_itm[src_len];
for (int i = 0; i < src_len; i++)
rv[i] = src[i];
Array_.Sort(rv, Pxd_itm_sorter._);
return rv;
}
}

View File

@@ -0,0 +1,364 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
class Pxd_itm_month_name extends Pxd_itm_base implements Pxd_itm_prototype {
public Pxd_itm_month_name(int ary_idx, byte[] name, int seg_idx, int seg_val) {Ctor(ary_idx); this.name = name; Seg_idx_(seg_idx); this.seg_val = seg_val;} private byte[] name;
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_month_name;}
@Override public int Eval_idx() {return 20;}
int 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;
}
@Override public void Eval(Pxd_parser state) {
state.Seg_idxs_(this, this.Seg_idx(), seg_val);
switch (this.Data_idx()) {
case 0: Eval_month_0(state); break;
case 1: Eval_month_1(state); break;
case 2: Eval_month_2(state); break;
default:
Pxd_itm[] data_ary = state.Data_ary();
int data_idx = this.Data_idx();
if (data_idx + 1 < data_ary.length) {
Pxd_itm_int itm_rhs = Pxd_itm_int_.CastOrNull(data_ary[data_idx + 1]);
if (itm_rhs.Digits() == 4) { // handle fmts of 1 January 2010
Eval_month_1(state);
return;
}
}
Eval_month_2(state);
break;
}
}
public void Eval_month_0(Pxd_parser state) {
Pxd_itm[] data_ary = state.Data_ary();
int data_ary_len = state.Data_ary_len();
switch (data_ary_len) {
case 1: break; // noop; nothing needs to be done
case 2: {
Pxd_itm_int itm_1 = Pxd_itm_int_.CastOrNull(data_ary[1]);
if (itm_1 == null) {return;} // trie: fail
switch (itm_1.Digits()) {
case 4: Pxd_eval_seg.Eval_as_y(state, itm_1); break;
default: Pxd_eval_seg.Eval_as_d(state, itm_1); break;
}
break;
}
default: // NOTE: handle invalid dates like January 2, 1999, 2000; DATE:2013-05-06
case 3: {
Pxd_itm_int itm_1 = Pxd_itm_int_.CastOrNull(data_ary[1]);
Pxd_itm_int itm_2 = Pxd_itm_int_.CastOrNull(data_ary[2]);
if (itm_1 == null || itm_2 == null) {return;} // trie: fail
if (itm_1.Digits() == 4) { // ASSUME: year since there are 4 digits; EX: May 2012
if (Pxd_eval_seg.Eval_as_y(state, itm_1)) return; // no error; return; otherwise continue below;
}
if (!Pxd_eval_seg.Eval_as_d(state, itm_1)) return;
if (!Pxd_eval_seg.Eval_as_y(state, itm_2)) return;
break;
}
}
}
public void Eval_month_1(Pxd_parser state) {
Pxd_itm[] data_ary = state.Data_ary();
int data_ary_len = state.Data_ary_len();
switch (data_ary_len) {
case 2: {
Pxd_itm_int itm_0 = Pxd_itm_int_.CastOrNull(data_ary[0]);
if (itm_0 == null) {return;} // trie: fail
switch (itm_0.Digits()) {
case 4: Pxd_eval_seg.Eval_as_y(state, itm_0); break;
default: Pxd_eval_seg.Eval_as_d(state, itm_0); break;
}
break;
}
default:
case 3: {
Pxd_itm_int itm_0 = Pxd_itm_int_.GetNearest(data_ary, this.Data_idx(), false);
Pxd_itm_int itm_2 = Pxd_itm_int_.GetNearest(data_ary, this.Data_idx(), true);
if (itm_0 == null || itm_2 == null) {return;} // trie: fail
switch (itm_0.Digits()) {
case 4:
if (!Pxd_eval_seg.Eval_as_y(state, itm_0)) return;
if (!Pxd_eval_seg.Eval_as_d(state, itm_2)) return;
break;
default:
if (itm_2.Digits() == 4) {
if (!Pxd_eval_seg.Eval_as_d(state, itm_0)) return;
if (!Pxd_eval_seg.Eval_as_y(state, itm_2)) return;
}
else { // 2 digits on either side of month; assume dd mm yy; EX: 03 Feb 01 -> 2001-02-03
if (!Pxd_eval_seg.Eval_as_d(state, itm_0)) return;
if (!Pxd_eval_seg.Eval_as_y(state, itm_2)) return;
}
break;
}
break;
}
}
}
public void Eval_month_2(Pxd_parser state) {
Pxd_itm[] data_ary = state.Data_ary();
int data_ary_len = state.Data_ary_len();
switch (data_ary_len) {
case 3: {
Pxd_itm_int itm_0 = Pxd_itm_int_.CastOrNull(data_ary[0]);
Pxd_itm_int itm_1 = Pxd_itm_int_.CastOrNull(data_ary[1]);
if (itm_0 == null || itm_1 == null) {return;} // trie: fail
switch (itm_0.Digits()) {
case 4:
if (!Pxd_eval_seg.Eval_as_y(state, itm_0)) return;
if (!Pxd_eval_seg.Eval_as_d(state, itm_1)) return;
break;
default:
if (itm_1.Digits() == 4) {
if (!Pxd_eval_seg.Eval_as_d(state, itm_0)) return;
if (!Pxd_eval_seg.Eval_as_y(state, itm_1)) return;
}
else { // 2 digits on either side of month; assume dd mm yy; EX: 03 Feb 01 -> 2001-02-03
if (!Pxd_eval_seg.Eval_as_d(state, itm_0)) return;
if (!Pxd_eval_seg.Eval_as_y(state, itm_1)) return;
}
break;
}
break;
}
}
}
@Override public void Time_ini(DateAdpBldr bldr) {
bldr.Seg_set(this.Seg_idx(), seg_val);
}
}
class Pxd_itm_unit extends Pxd_itm_base implements Pxd_itm_prototype {
public Pxd_itm_unit(int ary_idx, byte[] name, int seg_idx, int seg_multiple) {Ctor(ary_idx); this.name = name; Seg_idx_(seg_idx); this.seg_multiple = seg_multiple;}
public byte[] Name() {return name;} private byte[] name;
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_unit;}
@Override public int Eval_idx() {return 10;}
int seg_val = 1; int seg_multiple;
public Pxd_itm MakeNew(int ary_idx) {
return new Pxd_itm_unit(ary_idx, name, this.Seg_idx(), seg_val);
}
public void Unit_seg_val_(int v) { // handled by relative; EX: next year
seg_val = v; seg_multiple = 1;
eval_done_by_relative = true;
} private boolean eval_done_by_relative;
@Override public void Eval(Pxd_parser state) {
if (eval_done_by_relative) return;
state.Seg_idxs_(this, this.Seg_idx(), seg_val);
Pxd_itm[] tkns = state.Tkns();
Pxd_itm_int itm_int = Pxd_itm_int_.GetNearest(tkns, this.Ary_idx(), false);
state.Seg_idxs_(itm_int, Pxd_itm_base.Seg_idx_skip);
seg_val = itm_int.Val();
for (int i = itm_int.Ary_idx(); i > -1; i--) {
Pxd_itm itm = tkns[i];
switch (itm.Tkn_tid()) {
case Pxd_itm_.Tid_dash: // negative sign; stop;
seg_val *= -1;
i = -1;
break;
case Pxd_itm_.Tid_dot: case Pxd_itm_.Tid_int: case Pxd_itm_.Tid_ws: // ignore
break;
default: // word; stop;
i = -1;
break;
}
}
}
@Override public void Time_ini(DateAdpBldr bldr) {
DateAdp cur = bldr.Date();
if (cur == null) cur = DateAdp_.Now();
int val = seg_val * seg_multiple;
switch (this.Seg_idx()) {
case DateAdp_.SegIdx_second: cur = cur.Add_second(val); break;
case DateAdp_.SegIdx_minute: cur = cur.Add_minute(val); break;
case DateAdp_.SegIdx_hour : cur = cur.Add_hour (val); break;
case DateAdp_.SegIdx_day : cur = cur.Add_day (val); break;
case DateAdp_.SegIdx_month : cur = cur.Add_month (val); break;
case DateAdp_.SegIdx_year : cur = cur.Add_year (val); break;
default: throw Exc_.new_unhandled(this.Seg_idx());
}
bldr.Date_(cur);
}
}
class Pxd_itm_ago extends Pxd_itm_base implements Pxd_itm_prototype {
public Pxd_itm_ago(int ary_idx, int seg_idx) {Ctor(ary_idx); Seg_idx_(seg_idx);}
public byte[] Name() {return Name_ago;} public static final byte[] Name_ago = Bry_.new_a7("ago");
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_ago;}
@Override public int Eval_idx() {return 5;} // set to high priority so it can evaluate before unit_name
public Pxd_itm MakeNew(int ary_idx) {return new Pxd_itm_ago(ary_idx, this.Seg_idx());}
@Override public void Eval(Pxd_parser state) {
Pxd_itm[] tkns = state.Tkns();
int end = this.Ary_idx();
boolean unit_seen = false;
for (int i = end - 1; i > -1; i--) { // loop over tokens, moving backward
Pxd_itm itm = tkns[i];
switch (itm.Tkn_tid()) {
case Pxd_itm_.Tid_ws: break; // ignore ws
case Pxd_itm_.Tid_unit: unit_seen = true; break; // unit seen; flag
case Pxd_itm_.Tid_int:
if (unit_seen) { // only if unit seen, reverse int; EX: "1 month ago" effectively becomes "-1 month"
Pxd_itm_int itm_int = (Pxd_itm_int)itm;
itm_int.Val_(-itm_int.Val());
i = -1; // end loop
}
break;
default: break;
}
}
}
@Override public void Time_ini(DateAdpBldr bldr) {
}
}
class Pxd_itm_day_suffix extends Pxd_itm_base implements Pxd_itm_prototype {
public Pxd_itm_day_suffix(int ary_idx) {Ctor(ary_idx);}
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_day_suffix;}
@Override public int Eval_idx() {return 99;} // set to low priority so it can evaluate after day
public Pxd_itm MakeNew(int ary_idx) {return new Pxd_itm_day_suffix(ary_idx);}
@Override public void Eval(Pxd_parser state) {
Pxd_itm[] tkn_ary = state.Tkns();
int tkn_idx = this.Ary_idx();
if (tkn_idx == 0) state.Err_set(Pft_func_time_log.Invalid_day, Bry_fmtr_arg_.int_(Int_.MinValue));
Pxd_itm day_itm = tkn_ary[tkn_idx - 1];
if (day_itm.Seg_idx() != DateAdp_.SegIdx_day) {
state.Err_set(Pft_func_time_log.Invalid_day, Bry_fmtr_arg_.int_(Int_.MinValue));
}
}
public static final Pxd_itm_day_suffix _ = new Pxd_itm_day_suffix(); Pxd_itm_day_suffix() {}
}
class Pxd_itm_day_relative extends Pxd_itm_base implements Pxd_itm_prototype {
public Pxd_itm_day_relative(int adj, int ary_idx) {Ctor(ary_idx); this.adj = adj;}
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_day_relative;}
@Override public int Eval_idx() {return 5;}
public Pxd_itm MakeNew(int ary_idx) {return new Pxd_itm_day_relative(adj, ary_idx);}
@Override public void Eval(Pxd_parser state) {
}
@Override public void Time_ini(DateAdpBldr bldr) {
DateAdp date = DateAdp_.Now();
if (adj != 0) date = date.Add_day(adj);
bldr.Seg_set(DateAdp_.SegIdx_year , date.Year());
bldr.Seg_set(DateAdp_.SegIdx_month , date.Month());
bldr.Seg_set(DateAdp_.SegIdx_day , date.Day());
}
public static final Pxd_itm_day_relative
Today = new Pxd_itm_day_relative(0)
, Tomorrow = new Pxd_itm_day_relative(1)
, Yesterday = new Pxd_itm_day_relative(-1)
;
Pxd_itm_day_relative(int adj) {this.adj = adj;} private int adj;
}
class Pxd_itm_time_relative extends Pxd_itm_base implements Pxd_itm_prototype {
public Pxd_itm_time_relative(int ary_idx) {Ctor(ary_idx);}
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_time_relative;}
@Override public int Eval_idx() {return 5;}
public Pxd_itm MakeNew(int ary_idx) {return new Pxd_itm_time_relative(ary_idx);}
@Override public void Eval(Pxd_parser state) {
}
@Override public void Time_ini(DateAdpBldr bldr) {
DateAdp date = DateAdp_.Now();
bldr.Seg_set(DateAdp_.SegIdx_year , date.Year());
bldr.Seg_set(DateAdp_.SegIdx_month , date.Month());
bldr.Seg_set(DateAdp_.SegIdx_day , date.Day());
bldr.Seg_set(DateAdp_.SegIdx_hour , date.Hour());
bldr.Seg_set(DateAdp_.SegIdx_minute , date.Minute());
bldr.Seg_set(DateAdp_.SegIdx_second , date.Second());
bldr.Seg_set(DateAdp_.SegIdx_frac , date.Frac());
}
public static final Pxd_itm_time_relative
Now = new Pxd_itm_time_relative()
;
Pxd_itm_time_relative() {}
}
class Pxd_itm_unit_relative extends Pxd_itm_base implements Pxd_itm_prototype {
public Pxd_itm_unit_relative(int adj, int ary_idx) {Ctor(ary_idx); this.adj = adj;}
@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);}
@Override public void Eval(Pxd_parser state) {
Pxd_itm itm = Pxd_itm_.Find_fwd_by_tid(state.Tkns(), this.Ary_idx() + 1, Pxd_itm_.Tid_unit);
if (itm == null) state.Err_set(Pft_func_time_log.Invalid_date, Bry_fmtr_arg_.int_(adj));
Pxd_itm_unit unit_tkn = (Pxd_itm_unit)itm;
unit_tkn.Unit_seg_val_(adj);
}
@Override public void Time_ini(DateAdpBldr bldr) {
}
public static final Pxd_itm_unit_relative
Next = new Pxd_itm_unit_relative(1)
, Prev = new Pxd_itm_unit_relative(-1)
, This = new Pxd_itm_unit_relative(0)
;
Pxd_itm_unit_relative(int adj) {this.adj = adj;} private int adj;
}
class Pxd_itm_unixtime extends Pxd_itm_base implements Pxd_itm_prototype {
private long unixtime;
public Pxd_itm_unixtime(int ary_idx, int seg_idx) {Ctor(ary_idx); Seg_idx_(seg_idx);}
public byte[] Name() {return Name_const;} public static final byte[] Name_const = Bry_.new_a7("@");
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_unixtime;}
@Override public int Eval_idx() {return 5;} // set to high priority so it can evaluate number early
public Pxd_itm MakeNew(int ary_idx) {return new Pxd_itm_unixtime(ary_idx, this.Seg_idx());}
@Override public void Eval(Pxd_parser state) {
Pxd_itm[] tkns = state.Tkns();
unixtime = Pxd_itm_int_.Read_nearest_as_int_and_skip(state, tkns, this.Ary_idx(), true, Int_.MinValue);
}
@Override public void Time_ini(DateAdpBldr bldr) {
DateAdp date = DateAdp_.unixtime_utc_seconds_(unixtime);
bldr.Seg_set(DateAdp_.SegIdx_year , date.Year());
bldr.Seg_set(DateAdp_.SegIdx_month , date.Month());
bldr.Seg_set(DateAdp_.SegIdx_day , date.Day());
bldr.Seg_set(DateAdp_.SegIdx_hour , date.Hour());
bldr.Seg_set(DateAdp_.SegIdx_minute , date.Minute());
bldr.Seg_set(DateAdp_.SegIdx_second , date.Second());
bldr.Seg_set(DateAdp_.SegIdx_frac , date.Frac());
}
}
class Pxd_itm_dow_name extends Pxd_itm_base implements Pxd_itm_prototype {
private int dow_idx;
private byte[] dow_name;
public Pxd_itm_dow_name(int ary_idx, byte[] dow_name, int dow_idx) {Ctor(ary_idx); this.dow_name = dow_name; this.Seg_idx_(DateAdp_.SegIdx_dayOfWeek); this.dow_idx = dow_idx;}
@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);}
@Override public void Eval(Pxd_parser state) {
}
@Override public void Time_ini(DateAdpBldr bldr) {
DateAdp now = DateAdp_.Now();
int adj = dow_idx - now.DayOfWeek(); // adj = requested_dow - current_dow; EX: requesting Friday, and today is Wednesday; adj = 2 (4 - 2); DATE:2014-05-02
if (adj < 0) adj += 7; // requested_down is before current_dow; add 7 to get the next day
bldr.Date_(bldr.Date().Add_day(adj));
}
}
class Pxd_itm_iso8601_t extends Pxd_itm_base implements Pxd_itm_prototype {
public Pxd_itm_iso8601_t(int ary_idx, int seg_idx) {Ctor(ary_idx); Seg_idx_(seg_idx);}
public byte[] Name() {return Name_const;} public static final byte[] Name_const = Bry_.new_a7("T");
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_iso8601_t;}
@Override public int Eval_idx() {return 99;} // evaluate last
public Pxd_itm MakeNew(int ary_idx) {return new Pxd_itm_iso8601_t(ary_idx, this.Seg_idx());}
@Override public void Eval(Pxd_parser state) {
Pxd_itm hour = Next_non_ws_tkn(state.Tkns(), this.Ary_idx() + 1);
if (hour != null && hour.Seg_idx() == DateAdp_.SegIdx_hour) return; // next item is hour
state.Err_set(Pft_func_time_log.Invalid_hour, Bry_fmtr_arg_.bry_("T"));
}
@Override public void Time_ini(DateAdpBldr bldr) {}
private static Pxd_itm Next_non_ws_tkn(Pxd_itm[] tkns, int bgn) {
int len = tkns.length;
for (int i = bgn; i < len; i++) {
Pxd_itm itm = tkns[i];
if (itm.Tkn_tid() != Pxd_itm_.Tid_ws) return itm;
}
return null;
}
}

View File

@@ -0,0 +1,262 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
import gplx.core.btries.*;
class Pxd_parser {
byte[] src; int cur_pos, tkn_bgn_pos, src_len, tkn_type;
public Pxd_itm[] Tkns() {return tkns;} Pxd_itm[] tkns;
public int Tkns_len() {return tkns_len;} private int tkns_len;
public Pxd_itm[] Data_ary() {return data_ary;} Pxd_itm[] data_ary;
public int Data_ary_len() {return data_ary_len;} private int data_ary_len;
public int Colon_count;
public int[] Seg_idxs() {return seg_idxs;} private int[] seg_idxs = new int[DateAdp_.SegIdx__max]; // temp ary for storing current state
public boolean Seg_idxs_chk(int... ary) {
int len = ary.length;
for (int i = 0; i < len; i++)
if (ary[i] == Pxd_itm_base.Seg_idx_null) return false;
return true;
}
public void Seg_idxs_(Pxd_itm_int itm, int seg_idx) {Seg_idxs_(itm, seg_idx, itm.Val());}
public void Seg_idxs_(Pxd_itm_base itm, int seg_idx, int val) {
itm.Seg_idx_(seg_idx);
if (seg_idx >= 0) // ignore Seg_idx_null and Seg_idx_skip
seg_idxs[seg_idx] = val;
}
public void Err_set(Gfo_msg_itm itm, Bry_fmtr_arg... args) {
if (itm == null) return;
Bry_fmtr fmtr = itm.Fmtr();
fmtr.Bld_bfr(error_bfr, args);
} private Bry_bfr error_bfr = Bry_bfr.new_(32);
public DateAdp Parse(byte[] src, Bry_bfr error_bfr) {
Tokenize(src); // NOTE: should check if Tokenize failed, but want to be liberal as date parser is not fully implemented; this will always default to 1st day of year; DATE:2014-03-27
return Evaluate(src, error_bfr);
}
private boolean Tokenize(byte[] src) {
this.src = src; src_len = src.length;
tkns = new Pxd_itm[src_len]; tkns_len = 0;
tkn_type = Pxd_itm_.Tid_null; tkn_bgn_pos = -1;
cur_pos = 0;
Colon_count = 0;
error_bfr.Clear();
for (int i = 0; i < DateAdp_.SegIdx__max; i++)
seg_idxs[i] = Pxd_itm_base.Seg_idx_null;
while (cur_pos < src_len) {
byte b = src[cur_pos];
switch (b) {
case Byte_ascii.Space: case Byte_ascii.Tab: case Byte_ascii.Nl:
if (tkn_type != Pxd_itm_.Tid_ws) MakePrvTkn(cur_pos, Pxd_itm_.Tid_ws); break; // SEE:NOTE_1 for logic
case Byte_ascii.Dash: case Byte_ascii.Dot: case Byte_ascii.Colon: case Byte_ascii.Slash:
if (tkn_type != b) MakePrvTkn(cur_pos, b); break;
case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4:
case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9:
if (tkn_type != Pxd_itm_.Tid_int) MakePrvTkn(cur_pos, Pxd_itm_.Tid_int); break;
case Byte_ascii.Ltr_A: case Byte_ascii.Ltr_B: case Byte_ascii.Ltr_C: case Byte_ascii.Ltr_D: case Byte_ascii.Ltr_E:
case Byte_ascii.Ltr_F: case Byte_ascii.Ltr_G: case Byte_ascii.Ltr_H: case Byte_ascii.Ltr_I: case Byte_ascii.Ltr_J:
case Byte_ascii.Ltr_K: case Byte_ascii.Ltr_L: case Byte_ascii.Ltr_M: case Byte_ascii.Ltr_N: case Byte_ascii.Ltr_O:
case Byte_ascii.Ltr_P: case Byte_ascii.Ltr_Q: case Byte_ascii.Ltr_R: case Byte_ascii.Ltr_S: case Byte_ascii.Ltr_T:
case Byte_ascii.Ltr_U: case Byte_ascii.Ltr_V: case Byte_ascii.Ltr_W: case Byte_ascii.Ltr_X: case Byte_ascii.Ltr_Y: case Byte_ascii.Ltr_Z:
case Byte_ascii.Ltr_a: case Byte_ascii.Ltr_b: case Byte_ascii.Ltr_c: case Byte_ascii.Ltr_d: case Byte_ascii.Ltr_e:
case Byte_ascii.Ltr_f: case Byte_ascii.Ltr_g: case Byte_ascii.Ltr_h: case Byte_ascii.Ltr_i: case Byte_ascii.Ltr_j:
case Byte_ascii.Ltr_k: case Byte_ascii.Ltr_l: case Byte_ascii.Ltr_m: case Byte_ascii.Ltr_n: case Byte_ascii.Ltr_o:
case Byte_ascii.Ltr_p: case Byte_ascii.Ltr_q: case Byte_ascii.Ltr_r: case Byte_ascii.Ltr_s: case Byte_ascii.Ltr_t:
case Byte_ascii.Ltr_u: case Byte_ascii.Ltr_v: case Byte_ascii.Ltr_w: case Byte_ascii.Ltr_x: case Byte_ascii.Ltr_y: case Byte_ascii.Ltr_z:
case Byte_ascii.At:
MakePrvTkn(cur_pos, Pxd_itm_.Tid_null); // first, make prv tkn
Object o = trie.Match_bgn_w_byte(b, src, cur_pos, src_len); // now match String against tkn
if (o == null) return false; // unknown letter / word; exit now;
tkns[tkns_len] = ((Pxd_itm_prototype)o).MakeNew(tkns_len);
++tkns_len;
cur_pos = trie.Match_pos() - 1; // -1 b/c trie matches to next char, and ++ below
break;
case Byte_ascii.Comma: case Byte_ascii.Plus:
MakePrvTkn(cur_pos, Pxd_itm_.Tid_null);
tkns[tkns_len] = new Pxd_itm_sym(tkns_len, b);
++tkns_len;
break;
}
++cur_pos;
}
MakePrvTkn(cur_pos, Pxd_itm_.Tid_null);
return true;
}
private void MakePrvTkn(int cur_pos, int nxt_type) {
Pxd_itm itm = null;
switch (tkn_type) {
case Pxd_itm_.Tid_int:
int int_val = Bry_.Xto_int_or(src, tkn_bgn_pos, cur_pos, Int_.MinValue);
if (int_val == Int_.MinValue) {} // FUTURE: warn
int digits = cur_pos - tkn_bgn_pos;
switch (digits) {
case 14:
case 8:
itm = new Pxd_itm_int_dmy_14(tkns_len, Bry_.Mid(src, tkn_bgn_pos, cur_pos), digits); break;
case 6:
itm = new Pxd_itm_int_mhs_6(tkns_len, Bry_.Mid(src, tkn_bgn_pos, cur_pos)); break;
default:
itm = new Pxd_itm_int(tkns_len, digits, int_val); break;
}
break;
case Pxd_itm_.Tid_ws: itm = new Pxd_itm_ws(tkns_len); break;
case Pxd_itm_.Tid_dash: itm = new Pxd_itm_dash(tkns_len); break;
case Pxd_itm_.Tid_dot: itm = new Pxd_itm_dot(tkns_len); break;
case Pxd_itm_.Tid_colon: itm = new Pxd_itm_colon(tkns_len); break;
case Pxd_itm_.Tid_slash: itm = new Pxd_itm_slash(tkns_len); break;
case Pxd_itm_.Tid_null: break; // NOOP
}
if (itm != null) {
tkns[tkns_len] = itm;
++tkns_len;
}
tkn_type = nxt_type;
tkn_bgn_pos = cur_pos;
}
DateAdp Evaluate(byte[] src, Bry_bfr error) {
if (tkns_len == 0) {
Err_set(Pft_func_time_log.Invalid_day, Bry_fmtr_arg_.bry_(src));
return null;
}
Pxd_itm[] eval_ary = Pxd_itm_sorter.XtoAryAndSort(tkns, tkns_len);
MakeDataAry();
for (int i = 0; i < tkns_len; i++) {
eval_ary[i].Eval(this);
if (error_bfr.Len() != 0) {
error.Add_bfr_and_clear(error_bfr);
return DateAdp_.MinValue;
}
}
DateAdpBldr bldr = new DateAdpBldr(DateAdp_.Now().Year(), 1, 1, 0, 0, 0, 0);
for (int i = 0; i < tkns_len; i++) {
Pxd_itm itm = (Pxd_itm)tkns[i];
itm.Time_ini(bldr);
}
return bldr.Bld();
}
private void MakeDataAry() {
data_ary = new Pxd_itm[tkns_len]; data_ary_len = 0;
for (int i = 0; i < tkns_len; i++) {
Pxd_itm itm = tkns[i];
switch (itm.Tkn_tid()) {
case Pxd_itm_.Tid_month_name:
case Pxd_itm_.Tid_int:
itm.Data_idx_(data_ary_len);
data_ary[data_ary_len++] = itm;
break;
}
}
}
private static Btrie_slim_mgr trie = Pxd_parser_.Trie();
}
class Pxd_parser_ {
public static Btrie_slim_mgr Trie() {
if (trie == null) {
trie = Btrie_slim_mgr.ci_ascii_(); // NOTE:ci.ascii:MW_const.en
Init();
}
return trie;
} static Btrie_slim_mgr trie;
private static final String[] Names_month_full = {"january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december"};
private static final String[] Names_month_abrv = {"jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"};
private static final String[] Names_month_roman = {"I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII"};
private static final String[] Names_day_suffix = {"st", "nd", "rd", "th"};
private static final String[] Names_day_full = {"sunday", "monday", "tuesday", "wednesday" , "thursday", "friday", "saturday"};
private static final String[] Names_day_abrv = {"sun", "mon", "tue", "wed" , "thu", "fri", "sat"};
//TODO:
//private static final String[] Names_day_text = {"weekday", "weekdays"};
//private static final String[] Names_ordinal_num = {"first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth", "tenth", "eleventh", "twelfth"};
private static void Init_unit(int seg_idx, String... name_ary) {Init_unit(seg_idx, 1, name_ary);}
private static void Init_unit(int seg_idx, int seg_val, String... name_ary) {
int name_ary_len = name_ary.length;
for (int i = 0; i < name_ary_len; i++) {
byte[] name_bry = Bry_.new_u8(name_ary[i]);
trie.Add_obj(name_bry, new Pxd_itm_unit(-1, name_bry, seg_idx, seg_val));
}
}
public static final byte[]
Unit_name_month = Bry_.new_a7("month")
, Unit_name_day = Bry_.new_a7("day")
, Unit_name_hour = Bry_.new_a7("hour")
;
private static void Init() {
Init_reg_months(Names_month_full);
Init_reg_months(Names_month_abrv);
Init_reg_months(Names_month_roman);
Init_reg_month("sept", 9);
Init_reg_days_of_week(Names_day_full);
Init_reg_days_of_week(Names_day_abrv);
Init_unit(DateAdp_.SegIdx_second , "sec", "secs", "second", "seconds");
Init_unit(DateAdp_.SegIdx_minute , "min", "mins", "minute", "minutes");
Init_unit(DateAdp_.SegIdx_hour , "hour", "hours");
Init_unit(DateAdp_.SegIdx_day , "day", "days");
Init_unit(DateAdp_.SegIdx_day, 14 , "fortnight", "forthnight");
Init_unit(DateAdp_.SegIdx_month , "month", "months");
Init_unit(DateAdp_.SegIdx_year , "year", "years");
Init_unit(DateAdp_.SegIdx_day, 7 , "week", "weeks");
trie.Add_obj(Pxd_itm_ago.Name_ago, new Pxd_itm_ago(-1, -1));
Init_suffix(Names_day_suffix);
Init_relative();
trie.Add_obj(Pxd_itm_unixtime.Name_const, new Pxd_itm_unixtime(-1, -1));
trie.Add_obj(Pxd_itm_iso8601_t.Name_const, new Pxd_itm_iso8601_t(-1, -1));
}
private static void Init_reg_months(String[] names) {
for (int i = 0; i < names.length; i++)
Init_reg_month(names[i], i + Int_.Base1); // NOTE: Months are Base1: 1-12
}
private static void Init_reg_month(String name_str, int seg_val) {
byte[] name_ary = Bry_.new_u8(name_str);
trie.Add_obj(name_ary, new Pxd_itm_month_name(-1, name_ary, DateAdp_.SegIdx_month, seg_val));
}
private static void Init_reg_days_of_week(String[] ary) {
int len = ary.length;
for (int i = 0; i < len; i++) {
byte[] itm_bry = Bry_.new_u8(ary[i]);
trie.Add_obj(itm_bry, new Pxd_itm_dow_name(-1, itm_bry, i)); // NOTE: days are base0; 0-6
}
}
private static void Init_suffix(String[] suffix_ary) {
int len = suffix_ary.length;
for (int i = 0; i < len; i++) {
String suffix = suffix_ary[i];
trie.Add_obj(suffix, Pxd_itm_day_suffix._);
}
}
private static void Init_relative() {
trie.Add_obj("today", Pxd_itm_day_relative.Today);
trie.Add_obj("tomorrow", Pxd_itm_day_relative.Tomorrow);
trie.Add_obj("yesterday", Pxd_itm_day_relative.Yesterday);
trie.Add_obj("now", Pxd_itm_time_relative.Now);
trie.Add_obj("next", Pxd_itm_unit_relative.Next);
trie.Add_obj("last", Pxd_itm_unit_relative.Prev);
trie.Add_obj("previous", Pxd_itm_unit_relative.Prev);
trie.Add_obj("this", Pxd_itm_unit_relative.This);
}
}
/*
NOTE_1:parsing works by completing previous items and then setting current;
EX: "123 456"
1: tkn_type = null; b = number
complete tkn (note that tkn is null)
set tkn_type to number; set tkn_bgn to 0
2: b == number == tkn_type; noop
3: b == number == tkn_type; noop
4: b == space != tkn_type;
complete prv
create tkn with bgn = tkn_bgn and end = cur_pos
set tkn_type to space; set tkn_bgn to cur_pos
etc..
*/

View File

@@ -0,0 +1,95 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
import org.junit.*;
public class Pxd_parser_tst {
Bry_bfr bfr = Bry_bfr.new_(16); Pxd_parser parser = new Pxd_parser();
@Before public void init() {Tfds.Now_enabled_y_(); Tfds.Now_set(test_date);} DateAdp test_date = DateAdp_.parse_fmt("2012-02-27", "yyyy-MM-dd");
@After public void teardown() {Tfds.Now_enabled_n_();}
@Test public void Month_name_0__day__year() {tst_date_("Mar 2 2001" , "2001-03-02");} // y:Mar-02-2001;Mar.02.2001;Mar 02, 2001 n:Mar/02/2001;Feb,05,2011
@Test public void Month_name_0__day__year__bad_day() {tst_date_("Mar 32 2001" , "Invalid day: 32");}
@Test public void Month_name_0__day__year__bad_year() {tst_date_("Mar 3 999" , "0999-03-03");}
@Test public void Month_name_0__day__year__bad_day_year() {tst_date_("Mar 32 999" , "Invalid day: 32");}
@Test public void Month_name_0__year() {tst_date_("Mar 2001" , "2001-03-01");}
@Test public void Month_name_0__day() {tst_date_("Mar 02" , "2012-03-02");}
@Test public void Month_name_0__day_fail() {tst_date_("Mar 32" , "Invalid day: 32");}
@Test public void Month_name_0() {tst_date_("Mar" , "2012-03-01");} // y: ,.,.. Feb; n: / Feb, - Feb
@Test public void Month_name_1__day__year() {tst_date_("2 Mar 2001" , "2001-03-02");} // y: 3-Feb-2012; 3 Feb 2012;
@Test public void Month_name_1__year__day() {tst_date_("2001 Mar 02" , "2001-03-02");} // y: 2012-Feb-3 n:2012.Feb.3;2012 Feb 3; 2012,Feb,3;2012/Feb/3
@Test public void Month_name_1__day__year__guess() {tst_date_("02 Mar 01" , "2001-03-02");}
@Test public void Month_name_1__day() {tst_date_("02 Mar" , "2012-03-02");}
@Test public void Month_name_1__year() {tst_date_("2003 Mar" , "2003-03-01");}
@Test public void Month_name_2__day__year() {tst_date_("2001.02.Mar" , "2001-03-02");} // y: 2012.5.Feb; 2012 5 Feb n: 2012-5-Feb; 2012/5/Feb
@Test public void Year_0__month__day() {tst_date_("2001-03-31" , "2001-03-31");}
@Test public void Year_0__day__month__fail() {tst_date_("2001-31-03" , "Invalid month: 31");} // n:2012.31.03; 2012/31/03
@Test public void Year_0__month() {tst_date_("2001-03" , "2001-03-01");}
@Test public void Year_0() {tst_date_("2001" , "2001-01-01");}
@Test public void Year_1() {tst_date_("31-2001" , "Invalid date: 4 digit year must be either yyyy-##-## or ##-##-yyyy");} // n:31-2012; 31.2012; 31/2012; 03-2012; 03.2012; 03/2012
@Test public void Year_2__month__day() {tst_date_("03/31/2001" , "2001-03-31");} // n: 03.31.2012;03-31-2012
@Test public void Year_2__day__month() {tst_date_("31-03-2001" , "2001-03-31");} // y: 31.03.2012; n:31/03/2012
@Test public void Day_0__month__day() {tst_date_("31-03-02" , "2031-03-02");}
@Test public void Day_0__month__day_dot() {tst_date_("22.05.70" , "1970-05-22");} // PURPOSE: dmy when delimiter is dot
@Test public void Day_1__month__year() {tst_date_("03-31-02" , "2002-03-31");}
@Test public void Day_2__month__day() {tst_date_("03-02-31" , "2031-03-02");}
@Test public void Dmy_is_default() {tst_date_("03-04-05" , "2005-04-03");}
@Test public void Dmy_is_default_y4() {tst_date_("2-5-2000" , "2000-05-02");}
@Test public void Colon_hour_min() {tst_time_("01:02" , "01:02:00.000");}
@Test public void Colon_hour_min_second() {tst_time_("01:02:03" , "01:02:03.000");}
@Test public void Time_all() {tst_both_("04-03-05 06:07:08" , "2005-03-04 06:07:08.000");}
@Test public void Unit_day_pos() {tst_date_("+ 3 days" , "2012-03-01");}
@Test public void Unit_day_neg() {tst_date_("- 3 days" , "2012-02-24");}
@Test public void Unit_day_neg_w_day() {tst_date_("30 May 2012 -1 days" , "2012-05-29");} // PAGE:en.w:Main Page
@Test public void Unit_week() {tst_date_("- 1 week" , "2012-02-26");} // PURPOSE.FIX: "week" was not being handled; error on main Page; EX:da.wikipedia.org/Main_Page
@Test public void Time_len_6() {tst_time_("041526" , "04:15:26.000");}
@Test public void Err_one_num() {tst_time_("2" , "Invalid year: 2");} // occurs on some templates; PAGE:en.w:Voyager 1 and {{date}}
@Test public void Dmy_at_y_dot() {tst_date_("1.2.70" , "1970-02-01");} // PURPOSE: dmy when delimiter is dot
@Test public void Mdy_at_y_slash() {tst_date_("1/2/70" , "1970-01-02");} // PURPOSE: mdy when delimiter is slash
@Test public void Ago() {tst_date_("1 month ago" , "2012-01-27");}
private void tst_date_(String raw, String expd) {
byte[] raw_ary = Bry_.new_u8(raw);
DateAdp date = parser.Parse(raw_ary, bfr);
if (date == DateAdp_.MinValue)
Tfds.Eq(expd, bfr.Xto_str_and_clear(), raw);
else
Tfds.Eq(expd, date.XtoStr_fmt_yyyy_MM_dd());
}
private void tst_time_(String raw, String expd) {
byte[] raw_ary = Bry_.new_u8(raw);
DateAdp date = parser.Parse(raw_ary, bfr);
if (date == DateAdp_.MinValue)
Tfds.Eq(expd, bfr.Xto_str_and_clear(), raw);
else
Tfds.Eq(expd, date.XtoStr_fmt("HH:mm:ss.fff"));
}
private void tst_both_(String raw, String expd) {
byte[] raw_ary = Bry_.new_u8(raw);
DateAdp date = parser.Parse(raw_ary, bfr);
if (date == DateAdp_.MinValue)
Tfds.Eq(expd, bfr.Xto_str_and_clear(), raw);
else
Tfds.Eq(expd, date.XtoStr_fmt("yyyy-MM-dd HH:mm:ss.fff"));
}
}
/*
12:12 2012 5 Feb: pass
2012 5 Feb 12:12: fail
2012-Feb-5 12:12: pass (but 2012-02-01)
2012-Feb-05 12:12: pass (and 2012-02-05)
{{#time:Y-m-d H:i:s A|.....2012.-.-.Feb-09....}}
*/