2013-04-24 01:07:16 -05:00
% vim: ts=4 sw=4 et
2016-04-11 18:12:35 -05:00
% Copyright (c) 2013-2016 Jesse Gumm
2013-04-24 01:07:16 -05:00
% See LICENSE for licensing information.
%
2013-01-14 13:58:12 -06:00
- module ( qdate ) .
2013-04-29 18:55:36 -05:00
- export ( [
start / 0 ,
stop / 0
] ) .
2013-01-14 13:58:12 -06:00
- export ( [
2013-04-24 01:07:16 -05:00
to_string / 1 ,
to_string / 2 ,
to_string / 3 ,
2013-10-22 17:29:16 -05:00
to_string / 4 ,
2013-04-24 01:07:16 -05:00
to_date / 1 ,
to_date / 2 ,
2013-10-22 17:29:16 -05:00
to_date / 3 ,
2013-04-24 01:07:16 -05:00
to_now / 1 ,
2013-10-22 17:42:17 -05:00
to_now / 2 ,
2013-04-24 01:07:16 -05:00
to_unixtime / 1 ,
2013-10-22 17:42:17 -05:00
to_unixtime / 2 ,
2013-04-24 01:07:16 -05:00
unixtime / 0
2013-01-14 13:58:12 -06:00
] ) .
2015-11-07 11:33:16 -06:00
- export ( [
beginning_minute / 1 ,
2015-11-07 11:39:24 -06:00
beginning_minute / 0 ,
2015-11-07 11:33:16 -06:00
beginning_hour / 1 ,
2015-11-07 11:39:24 -06:00
beginning_hour / 0 ,
2015-11-07 11:33:16 -06:00
beginning_day / 1 ,
2015-11-07 11:39:24 -06:00
beginning_day / 0 ,
2015-11-07 11:33:16 -06:00
%beginning_week/2, %% needs to be /2 because we also need to define what day is considered "beginning of week", since some calendars do sunday and some do monday. We'll hold off on implementation here
beginning_month / 1 ,
2015-11-07 11:39:24 -06:00
beginning_month / 0 ,
beginning_year / 1 ,
beginning_year / 0
2015-11-07 11:33:16 -06:00
] ) .
2016-04-18 20:02:34 -05:00
- export ( [
end_minute / 1 ,
end_minute / 0 ,
end_hour / 1 ,
end_hour / 0 ,
end_day / 1 ,
end_day / 0 ,
end_month / 1 ,
end_month / 0 ,
end_year / 1 ,
end_year / 0
] ) .
2013-09-12 20:14:49 -05:00
- export ( [
compare / 2 ,
2016-02-24 11:09:28 -06:00
compare / 3 ,
between / 2 ,
2016-02-24 13:09:33 -06:00
between / 3 ,
between / 5
2013-09-12 20:14:49 -05:00
] ) .
2014-08-22 23:47:39 -05:00
- export ( [
add_seconds / 2 ,
2015-04-29 12:25:42 -05:00
add_seconds / 1 ,
2014-08-22 23:47:39 -05:00
add_minutes / 2 ,
2015-04-29 12:25:42 -05:00
add_minutes / 1 ,
2014-08-22 23:47:39 -05:00
add_hours / 2 ,
2015-04-29 12:25:42 -05:00
add_hours / 1 ,
2014-08-22 23:47:39 -05:00
add_days / 2 ,
2015-04-29 12:25:42 -05:00
add_days / 1 ,
2014-08-22 23:47:39 -05:00
add_weeks / 2 ,
2015-04-29 12:25:42 -05:00
add_weeks / 1 ,
2014-08-22 23:47:39 -05:00
add_months / 2 ,
2015-04-29 12:25:42 -05:00
add_months / 1 ,
2014-08-22 23:47:39 -05:00
add_years / 2 ,
2015-04-29 12:25:42 -05:00
add_years / 1 ,
2016-03-05 15:16:03 -06:00
add_unit / 2 ,
add_unit / 3 ,
2014-08-22 23:47:39 -05:00
add_date / 2
] ) .
2015-11-06 17:03:16 -06:00
- export ( [
range / 4 ,
range_seconds / 3 ,
range_minutes / 3 ,
range_hours / 3 ,
range_days / 3 ,
range_weeks / 3 ,
range_months / 3 ,
range_years / 3
] ) .
2013-03-25 11:52:14 -05:00
- export ( [
2013-04-24 01:07:16 -05:00
register_parser / 2 ,
register_parser / 1 ,
deregister_parser / 1 ,
deregister_parsers / 0 ,
2014-08-30 15:53:19 -05:00
get_parsers / 0 ,
2013-04-24 01:07:16 -05:00
register_format / 2 ,
deregister_format / 1 ,
2014-08-30 15:53:19 -05:00
get_formats / 0 ,
2013-04-24 01:07:16 -05:00
set_timezone / 1 ,
set_timezone / 2 ,
get_timezone / 0 ,
get_timezone / 1 ,
clear_timezone / 0 ,
clear_timezone / 1
2013-03-25 11:52:14 -05:00
] ) .
2013-01-15 17:33:30 -06:00
2016-03-05 15:16:03 -06:00
- export ( [
parse_relative / 1
] ) .
2013-01-15 17:33:30 -06:00
2013-01-14 13:58:12 -06:00
%% Exported for API compatibility with ec_date
- export ( [
2013-04-24 01:07:16 -05:00
format / 1 , format / 2 ,
nparse / 1 ,
parse / 1
2013-01-14 13:58:12 -06:00
] ) .
2013-01-15 17:33:30 -06:00
%% This the value in gregorian seconds for jan 1st 1970, 12am
%% It's used to convert to and from unixtime, since unixtime starts
%% 1970-01-01 12:00am
2013-03-06 17:19:08 -06:00
- define ( UNIXTIME_BASE , 62167219200 ) .
2013-03-24 14:00:11 -05:00
2013-01-14 13:58:12 -06:00
2013-03-25 11:52:14 -05:00
- define ( DETERMINE_TZ , determine_timezone ( ) ) .
2013-10-22 17:29:16 -05:00
- define ( DEFAULT_DISAMBIG , prefer_standard ) .
- define ( else , true ) .
2013-03-25 11:52:14 -05:00
2013-04-29 18:55:36 -05:00
start ( ) - >
2015-04-30 14:31:41 -05:00
application : load ( qdate ) .
2013-04-29 18:55:36 -05:00
stop ( ) - >
2015-04-30 14:31:41 -05:00
ok .
2013-03-25 11:52:14 -05:00
2013-01-14 13:58:12 -06:00
to_string ( Format ) - >
2013-09-12 19:34:14 -05:00
to_string ( Format , os : timestamp ( ) ) .
2013-01-14 13:58:12 -06:00
to_string ( Format , Date ) - >
2013-04-24 01:07:16 -05:00
to_string ( Format , ? DETERMINE_TZ , Date ) .
2013-02-21 22:43:02 -06:00
2013-10-22 17:29:16 -05:00
to_string ( Format , ToTZ , Date ) - >
to_string ( Format , ToTZ , ? DEFAULT_DISAMBIG , Date ) .
to_string ( FormatKey , ToTZ , Disambiguate , Date ) when is_atom ( FormatKey ) orelse is_tuple ( FormatKey ) - >
2013-04-24 01:07:16 -05:00
Format = case qdate_srv : get_format ( FormatKey ) of
undefined - > throw ( { undefined_format_key , FormatKey } ) ;
F - > F
end ,
2013-10-22 17:29:16 -05:00
to_string ( Format , ToTZ , Disambiguate , Date ) ;
to_string ( Format , ToTZ , Disambiguate , Date ) when is_binary ( Format ) - >
list_to_binary ( to_string ( binary_to_list ( Format ) , ToTZ , Disambiguate , Date ) ) ;
to_string ( Format , ToTZ , Disambiguate , Date ) when is_list ( Format ) - >
2013-04-24 01:07:16 -05:00
%% it may seem odd that we're ensuring it here, and then again
%% as one of the last steps of the to_date process, but we need
%% the actual name for the strings for the PHP "T" and "e", so
%% we extract the Timezone in case ToTZ is actually a timezone key
%% Then we can pass it on to to_date as well. That way we don't have
%% to do it twice, since it's already ensured.
ActualToTZ = ensure_timezone ( ToTZ ) ,
2013-10-22 17:29:16 -05:00
case to_date ( ActualToTZ , Disambiguate , Date ) of
{ ambiguous , Standard , Daylight } - >
{ ambiguous ,
to_string_worker ( Format , ActualToTZ , prefer_standard , Standard ) ,
to_string_worker ( Format , ActualToTZ , prefer_daylight , Daylight ) } ;
ActualDate - >
case tz_name ( ActualDate , Disambiguate , ActualToTZ ) of
{ ambiguous , _ , _ } - >
{ ambiguous ,
to_string_worker ( Format , ActualToTZ , prefer_standard , ActualDate ) ,
to_string_worker ( Format , ActualToTZ , prefer_daylight , ActualDate ) } ;
_ - >
to_string_worker ( Format , ActualToTZ , Disambiguate , ActualDate )
end
end .
2013-04-22 22:13:24 -05:00
2013-10-22 17:29:16 -05:00
to_string_worker ( [ ] , _ , _ , _ ) - >
2013-04-24 01:07:16 -05:00
" " ;
2014-01-17 11:08:20 +08:00
to_string_worker ( [ $\\ , H | RestFormat ] , ToTZ , Disamb , Date ) - >
[ H | to_string_worker ( RestFormat , ToTZ , Disamb , Date ) ] ;
2013-10-22 17:29:16 -05:00
to_string_worker ( [ $e | RestFormat ] , ToTZ , Disamb , Date ) - >
ToTZ ++ to_string_worker ( RestFormat , ToTZ , Disamb , Date ) ;
to_string_worker ( [ $I | RestFormat ] , ToTZ , Disamb , Date ) - >
2013-04-24 01:07:16 -05:00
I = case localtime_dst : check ( Date , ToTZ ) of
is_in_dst - > " 1 " ;
is_not_in_dst - > " 0 " ;
ambiguous_time - > " ? "
end ,
2013-10-22 17:29:16 -05:00
I ++ to_string_worker ( RestFormat , ToTZ , Disamb , Date ) ;
to_string_worker ( [ H | RestFormat ] , ToTZ , Disamb , Date ) when H == $O orelse H == $P - >
Shift = get_timezone_shift ( ToTZ , Disamb , Date ) ,
2013-04-24 01:07:16 -05:00
Separator = case H of
$O - > " " ;
$P - > " : "
end ,
2013-10-22 17:29:16 -05:00
format_shift ( Shift , Separator ) ++ to_string_worker ( RestFormat , ToTZ , Disamb , Date ) ;
to_string_worker ( [ $T | RestFormat ] , ToTZ , Disamb , Date ) - >
ShortName = tz_name ( Date , Disamb , ToTZ ) ,
ShortName ++ to_string_worker ( RestFormat , ToTZ , Disamb , Date ) ;
to_string_worker ( [ $Z | RestFormat ] , ToTZ , Disamb , Date ) - >
{ Sign , Hours , Mins } = get_timezone_shift ( ToTZ , Disamb , Date ) ,
2013-04-24 01:07:16 -05:00
Seconds = ( Hours * 3600 ) + ( Mins * 60 ) ,
2013-10-22 17:29:16 -05:00
atom_to_list ( Sign ) ++ integer_to_list ( Seconds ) ++ to_string_worker ( RestFormat , ToTZ , Disamb , Date ) ;
to_string_worker ( [ $r | RestFormat ] , ToTZ , Disamb , Date ) - >
2013-04-24 01:07:16 -05:00
NewFormat = " D, d M Y H:i:s O " ,
2013-10-22 17:29:16 -05:00
to_string_worker ( NewFormat , ToTZ , Disamb , Date ) ++ to_string_worker ( RestFormat , ToTZ , Disamb , Date ) ;
to_string_worker ( [ $c | RestFormat ] , ToTZ , Disamb , Date ) - >
2013-04-24 01:07:16 -05:00
Format1 = " Y-m-d " ,
Format2 = " H:i:sP " ,
2013-10-22 17:29:16 -05:00
to_string_worker ( Format1 , ToTZ , Disamb , Date )
2013-04-24 01:07:16 -05:00
++ " T "
2013-10-22 17:29:16 -05:00
++ to_string_worker ( Format2 , ToTZ , Disamb , Date )
++ to_string_worker ( RestFormat , ToTZ , Disamb , Date ) ;
to_string_worker ( [ H | RestFormat ] , ToTZ , Disamb , Date ) - >
ec_date : format ( [ H ] , Date ) ++ to_string_worker ( RestFormat , ToTZ , Disamb , Date ) .
tz_name ( Date , Disambiguate , ToTZ ) - >
case localtime : tz_name ( Date , ToTZ ) of
{ ShortName , _ } when is_list ( ShortName ) - >
ShortName ;
{ { ShortStandard , _ } , { ShortDST , _ } } - >
case Disambiguate of
prefer_standard - > ShortStandard ;
prefer_daylight - > ShortDST ;
both - > { ambiguous , ShortStandard , ShortDST }
end
end .
2013-04-24 01:07:16 -05:00
2013-04-22 22:13:24 -05:00
format_shift ( { Sign , Hours , Mins } , Separator ) - >
2013-04-24 01:07:16 -05:00
SignStr = atom_to_list ( Sign ) ,
MinStr = leading_zero ( Mins ) ,
HourStr = leading_zero ( Hours ) ,
SignStr ++ HourStr ++ Separator ++ MinStr .
2013-04-22 22:13:24 -05:00
leading_zero ( I ) when I < 10 - >
2013-04-24 01:07:16 -05:00
" 0 " ++ integer_to_list ( I ) ;
2013-04-22 22:13:24 -05:00
leading_zero ( I ) - >
2013-04-24 01:07:16 -05:00
integer_to_list ( I ) .
2013-04-22 22:13:24 -05:00
2013-01-14 13:58:12 -06:00
format ( Format ) - >
2013-04-24 01:07:16 -05:00
to_string ( Format ) .
2013-01-14 13:58:12 -06:00
format ( Format , Date ) - >
2013-04-24 01:07:16 -05:00
to_string ( Format , Date ) .
2013-01-14 13:58:12 -06:00
parse ( String ) - >
2013-04-24 01:07:16 -05:00
to_date ( String ) .
2013-01-14 13:58:12 -06:00
nparse ( String ) - >
2013-04-24 01:07:16 -05:00
to_now ( String ) .
2013-01-14 13:58:12 -06:00
2013-02-21 22:43:02 -06:00
to_date ( RawDate ) - >
2013-04-29 18:55:36 -05:00
to_date ( ? DETERMINE_TZ , RawDate ) .
2013-02-21 22:43:02 -06:00
2013-10-22 17:29:16 -05:00
to_date ( ToTZ , RawDate ) - >
to_date ( ToTZ , ? DEFAULT_DISAMBIG , RawDate ) .
to_date ( ToTZ , Disambiguate , RawDate ) when is_binary ( RawDate ) - >
to_date ( ToTZ , Disambiguate , binary_to_list ( RawDate ) ) ;
to_date ( ToTZ , Disambiguate , RawDate ) when is_binary ( ToTZ ) - >
to_date ( binary_to_list ( ToTZ ) , Disambiguate , RawDate ) ;
to_date ( ToTZ , Disambiguate , RawDate ) - >
2013-04-24 01:07:16 -05:00
{ ExtractedDate , ExtractedTZ } = extract_timezone ( RawDate ) ,
{ RawDate3 , FromTZ } = case try_registered_parsers ( RawDate ) of
undefined - >
{ ExtractedDate , ExtractedTZ } ;
{ ParsedDate , undefined } - >
{ ParsedDate , ExtractedTZ } ;
{ ParsedDate , ParsedTZ } - >
{ ParsedDate , ParsedTZ }
2016-03-05 13:51:45 -06:00
end ,
2013-04-29 22:16:31 -05:00
try raw_to_date ( RawDate3 ) of
D = { { _ , _ , _ } , { _ , _ , _ } } - >
2015-10-14 16:13:42 +02:00
date_tz_to_tz ( D , Disambiguate , FromTZ , ToTZ ) ;
{ { Year , Month , Date } , { Hour , Minute , Second , _ Millis } } - >
date_tz_to_tz ( { { Year , Month , Date } , { Hour , Minute , Second } } , Disambiguate , FromTZ , ToTZ )
2013-04-29 22:16:31 -05:00
catch
_ : _ - >
case raw_to_date ( RawDate ) of
D2 = { { _ , _ , _ } , { _ , _ , _ } } - >
2013-10-22 17:29:16 -05:00
date_tz_to_tz ( D2 , Disambiguate , ? DETERMINE_TZ , ToTZ )
2013-04-29 22:16:31 -05:00
end
end .
2013-04-24 01:07:16 -05:00
2013-09-12 20:14:49 -05:00
%% This converts dates without regard to timezone.
%% Unixtime just goes to UTC
raw_to_date ( Unixtime ) when is_integer ( Unixtime ) - >
unixtime_to_date ( Unixtime ) ;
raw_to_date ( DateString ) when is_list ( DateString ) - >
ec_date : parse ( DateString , get_deterministic_datetime ( ) ) ;
raw_to_date ( Now = { _ , _ , _ } ) - >
calendar : now_to_datetime ( Now ) ;
raw_to_date ( Date = { { _ , _ , _ } , { _ , _ , _ } } ) - >
Date .
get_deterministic_datetime ( ) - >
DateZero = { 1970 , 1 , 1 } ,
TimeZero = { 0 , 0 , 0 } ,
case application : get_env ( qdate , deterministic_parsing ) of
{ ok , { zero , zero } } - > { DateZero , TimeZero } ;
{ ok , { zero , now } } - > { DateZero , time ( ) } ;
{ ok , { now , zero } } - > { date ( ) , TimeZero } ;
{ ok , { now , now } } - > { date ( ) , time ( ) } ;
undefined - > { DateZero , TimeZero } ;
{ ok , Val } - > throw ( { invalid_env_var , { qdate , deterministic_parsing , Val } } )
end .
2013-10-22 17:42:17 -05:00
to_unixtime ( Date ) - >
to_unixtime ( ? DEFAULT_DISAMBIG , Date ) .
2013-09-12 20:14:49 -05:00
2013-10-22 17:42:17 -05:00
to_unixtime ( _ , Unixtime ) when is_integer ( Unixtime ) - >
2013-09-12 20:14:49 -05:00
Unixtime ;
2016-03-05 15:16:03 -06:00
to_unixtime ( _ , { MegaSecs , Secs , _ } ) when is_integer ( MegaSecs ) , is_integer ( Secs ) - >
2013-09-12 20:14:49 -05:00
MegaSecs * 1000000 + Secs ;
2013-10-22 17:42:17 -05:00
to_unixtime ( Disamb , ToParse ) - >
2013-09-12 20:14:49 -05:00
%% We want to treat all unixtimes as GMT
2013-10-22 17:42:17 -05:00
case to_date ( " GMT " , Disamb , ToParse ) of
{ ambiguous , Standard , Daylight } - >
{ ambiguous ,
calendar : datetime_to_gregorian_seconds ( Standard ) - ? UNIXTIME_BASE ,
calendar : datetime_to_gregorian_seconds ( Daylight ) - ? UNIXTIME_BASE } ;
Date - >
calendar : datetime_to_gregorian_seconds ( Date ) - ? UNIXTIME_BASE
end .
2013-09-12 20:14:49 -05:00
unixtime ( ) - >
to_unixtime ( os : timestamp ( ) ) .
2013-10-22 17:42:17 -05:00
to_now ( Date ) - >
to_now ( ? DEFAULT_DISAMBIG , Date ) .
to_now ( _ , Now = { _ , _ , _ } ) - >
2013-09-12 20:14:49 -05:00
Now ;
2013-10-22 17:42:17 -05:00
to_now ( Disamb , ToParse ) - >
case to_unixtime ( Disamb , ToParse ) of
{ ambiguous , Standard , Daylight } - >
{ ambiguous ,
unixtime_to_now ( Standard ) ,
unixtime_to_now ( Daylight ) } ;
Unixtime - >
unixtime_to_now ( Unixtime )
end .
2013-09-12 20:14:49 -05:00
2015-11-07 11:33:16 -06:00
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Beginning/Truncation %%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2015-11-07 11:39:24 -06:00
beginning_minute ( ) - >
beginning_minute ( { date ( ) , time ( ) } ) .
2015-11-07 11:33:16 -06:00
beginning_minute ( Date ) - >
2016-04-20 19:36:06 -05:00
{ { Y , M , D } , { H , I , _ } } = to_date ( Date ) ,
{ { Y , M , D } , { H , I , 0 } } .
2015-11-07 11:33:16 -06:00
2015-11-07 11:39:24 -06:00
beginning_hour ( ) - >
beginning_hour ( { date ( ) , time ( ) } ) .
2015-11-07 11:33:16 -06:00
beginning_hour ( Date ) - >
{ { Y , M , D } , { H , _ , _ } } = to_date ( Date ) ,
{ { Y , M , D } , { H , 0 , 0 } } .
2015-11-07 11:39:24 -06:00
beginning_day ( ) - >
2016-05-19 03:56:43 +00:00
beginning_day ( unixtime ( ) ) .
2015-11-07 11:39:24 -06:00
2015-11-07 11:33:16 -06:00
beginning_day ( Date ) - >
{ { Y , M , D } , { _ , _ , _ } } = to_date ( Date ) ,
{ { Y , M , D } , { 0 , 0 , 0 } } .
2015-11-07 11:39:24 -06:00
beginning_month ( ) - >
beginning_month ( { date ( ) , time ( ) } ) .
2015-11-07 11:33:16 -06:00
beginning_month ( Date ) - >
{ { Y , M , _ } , { _ , _ , _ } } = to_date ( Date ) ,
{ { Y , M , 1 } , { 0 , 0 , 0 } } .
2015-11-07 11:39:24 -06:00
beginning_year ( ) - >
beginning_year ( { date ( ) , time ( ) } ) .
2015-11-07 11:33:16 -06:00
beginning_year ( Date ) - >
{ { Y , _ , _ } , { _ , _ , _ } } = to_date ( Date ) ,
{ { Y , 1 , 1 } , { 0 , 0 , 0 } } .
2016-04-18 20:02:34 -05:00
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%% End of Period (day/hour, etc) %%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
end_minute ( ) - >
end_minute ( { date ( ) , time ( ) } ) .
end_minute ( Date ) - >
{ { Y , M , D } , { H , I , _ } } = to_date ( Date ) ,
{ { Y , M , D } , { H , I , 59 } } .
end_hour ( ) - >
end_hour ( { date ( ) , time ( ) } ) .
end_hour ( Date ) - >
{ { Y , M , D } , { H , _ , _ } } = to_date ( Date ) ,
{ { Y , M , D } , { H , 59 , 59 } } .
end_day ( ) - >
end_day ( { date ( ) , time ( ) } ) .
end_day ( Date ) - >
{ { Y , M , D } , _ } = to_date ( Date ) ,
{ { Y , M , D } , { 23 , 59 , 59 } } .
end_month ( ) - >
end_month ( { date ( ) , time ( ) } ) .
end_month ( Date ) - >
Beginning = beginning_month ( Date ) ,
add_seconds ( - 1 , add_months ( 1 , Beginning ) ) .
end_year ( ) - >
end_year ( { date ( ) , time ( ) } ) .
end_year ( Date ) - >
{ { Y , _ , _ } , _ } = to_date ( Date ) ,
{ { Y , 12 , 31 } , { 23 , 59 , 59 } } .
2013-09-12 20:14:49 -05:00
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Comparisons %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
compare ( A , B ) - >
NowA = to_now ( A ) ,
NowB = to_now ( B ) ,
if
NowA == NowB - > 0 ;
NowA < NowB - > - 1 ;
NowA > NowB - > 1
end .
compare ( A , Op , B ) - >
Comp = compare ( A , B ) ,
case Op of
'==' - > Comp =:= 0 ;
'=' - > Comp =:= 0 ;
'!=' - > Comp =/= 0 ;
'=/=' - > Comp =/= 0 ;
'/=' - > Comp =/= 0 ;
2016-03-05 13:51:45 -06:00
'before' - > Comp =:= - 1 ;
2013-09-12 20:14:49 -05:00
'<' - > Comp =:= - 1 ;
'<=' - > Comp =:= - 1 orelse Comp =:= 0 ;
'=<' - > Comp =:= - 1 orelse Comp =:= 0 ;
2016-03-05 13:51:45 -06:00
'after' - > Comp =:= 1 ;
2013-09-12 20:14:49 -05:00
'>' - > Comp =:= 1 ;
'>=' - > Comp =:= 1 orelse Comp =:= 0 ;
'=>' - > Comp =:= 1 orelse Comp =:= 0
end .
2016-02-24 11:09:28 -06:00
between ( A , B ) - >
2016-02-24 13:09:33 -06:00
between ( A , unixtime ( ) , B ) .
2016-02-24 11:09:28 -06:00
2016-02-24 13:09:33 -06:00
between ( A , Date , B ) - >
between ( A , '=<' , Date , '=<' , B ) .
between ( A , Op1 , Date , Op2 , B ) - >
compare ( A , Op1 , Date ) andalso compare ( Date , Op2 , B ) .
2016-02-24 11:09:28 -06:00
2014-08-22 23:47:39 -05:00
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Date Math %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
add_seconds ( Seconds , Date ) - >
to_unixtime ( Date ) + Seconds .
2015-04-29 12:25:42 -05:00
add_seconds ( Seconds ) - >
add_seconds ( Seconds , os : timestamp ( ) ) .
2014-08-22 23:47:39 -05:00
add_minutes ( Minutes , Date ) - >
add_seconds ( Minutes * 60 , Date ) .
2015-04-29 12:25:42 -05:00
add_minutes ( Minutes ) - >
add_minutes ( Minutes , os : timestamp ( ) ) .
2014-08-22 23:47:39 -05:00
add_hours ( Hours , Date ) - >
add_seconds ( Hours * 3600 , Date ) .
2015-04-29 12:25:42 -05:00
add_hours ( Hours ) - >
add_hours ( Hours , os : timestamp ( ) ) .
2014-08-22 23:47:39 -05:00
add_days ( Days , Date0 ) - >
{ { Y , M , D } , Time } = to_date ( Date0 ) ,
to_unixtime ( fix_maybe_improper_date ( { { Y , M , D + Days } , Time } ) ) .
2015-04-29 12:25:42 -05:00
add_days ( Days ) - >
add_days ( Days , os : timestamp ( ) ) .
2014-08-22 23:47:39 -05:00
add_weeks ( Weeks , Date ) - >
add_days ( Weeks * 7 , Date ) .
2015-04-29 12:25:42 -05:00
add_weeks ( Weeks ) - >
add_weeks ( Weeks , os : timestamp ( ) ) .
2014-08-22 23:47:39 -05:00
add_months ( Months , Date ) - >
{ { Y , M , D } , Time } = to_date ( Date ) ,
2014-08-23 01:22:15 -05:00
{ TargetYear , TargetMonth } = fix_year_month ( { Y , M + Months } ) ,
DaysInMonth = calendar : last_day_of_the_month ( TargetYear , TargetMonth ) ,
NewD = lists : min ( [ DaysInMonth , D ] ) ,
to_unixtime ( fix_maybe_improper_date ( { { Y , M + Months , NewD } , Time } ) ) .
2014-08-22 23:47:39 -05:00
2015-04-29 12:25:42 -05:00
add_months ( Months ) - >
add_months ( Months , os : timestamp ( ) ) .
2014-08-22 23:47:39 -05:00
add_years ( Years , Date ) - >
{ { Y , M , D } , Time } = to_date ( Date ) ,
2014-08-23 01:22:15 -05:00
TargetYear = Y + Years ,
NewD = case M of
2 - >
DaysInMonth = calendar : last_day_of_the_month ( TargetYear , M ) ,
lists : min ( [ DaysInMonth , D ] ) ;
_ - >
D
end ,
to_unixtime ( { { Y + Years , M , NewD } , Time } ) .
2014-08-22 23:47:39 -05:00
2015-04-29 12:25:42 -05:00
add_years ( Years ) - >
add_years ( Years , os : timestamp ( ) ) .
2016-03-05 15:16:03 -06:00
add_unit ( second , Value , Date ) - >
add_unit ( seconds , Value , Date ) ;
add_unit ( seconds , Value , Date ) - >
add_seconds ( Value , Date ) ;
add_unit ( minute , Value , Date ) - >
add_unit ( minutes , Value , Date ) ;
add_unit ( minutes , Value , Date ) - >
add_minutes ( Value , Date ) ;
add_unit ( hour , Value , Date ) - >
add_unit ( hours , Value , Date ) ;
add_unit ( hours , Value , Date ) - >
add_hours ( Value , Date ) ;
add_unit ( day , Value , Date ) - >
add_unit ( days , Value , Date ) ;
add_unit ( days , Value , Date ) - >
add_days ( Value , Date ) ;
add_unit ( week , Value , Date ) - >
add_unit ( weeks , Value , Date ) ;
add_unit ( weeks , Value , Date ) - >
add_weeks ( Value , Date ) ;
add_unit ( month , Value , Date ) - >
add_unit ( months , Value , Date ) ;
add_unit ( months , Value , Date ) - >
add_months ( Value , Date ) ;
add_unit ( year , Value , Date ) - >
add_unit ( years , Value , Date ) ;
add_unit ( years , Value , Date ) - >
add_years ( Value , Date ) .
add_unit ( Unit , Value ) - >
add_unit ( Unit , Value , os : timestamp ( ) ) .
2014-08-22 23:47:39 -05:00
add_date ( { { AddY , AddM , AddD } , { AddH , AddI , AddS } } , Date ) - >
{ { Y , M , D } , { H , I , S } } = to_date ( Date ) ,
Date1 = fix_maybe_improper_date ( { { Y + AddY , M + AddM , D + AddD } , { H , I , S } } ) ,
Date2 = to_unixtime ( Date1 ) ,
Date2 + AddS + ( AddI * 60 ) + ( AddH * 3600 ) .
- define ( IS_LEAP_YEAR ( Y ) , ( Y rem 4 =:= 0 andalso
( Y rem 100 =/= 0
orelse Y rem 400 =:= 0 ) ) ) .
fix_maybe_improper_date ( { Date0 , Time } ) - >
Date = fmid ( Date0 ) ,
{ Date , Time } .
2014-08-23 01:22:15 -05:00
fix_year_month ( { Y , M } ) when M > 12 - >
2014-08-22 23:47:39 -05:00
YearsOver = M div 12 ,
2014-08-23 01:22:15 -05:00
{ Y + YearsOver , M - ( YearsOver * 12 ) } ;
fix_year_month ( { Y , M } ) when M < 1 - >
YearsUnder = ( abs ( M - 1 ) div 12 ) + 1 ,
{ Y - YearsUnder , M + ( YearsUnder * 12 ) } ;
fix_year_month ( { Y , M } ) - >
{ Y , M } .
fmid ( { Y , M , D } ) when M > 12 ;
M < 1 - >
{ NewY , NewM } = fix_year_month ( { Y , M } ) ,
fmid ( { NewY , NewM , D } ) ;
2014-08-22 23:47:39 -05:00
fmid ( { Y , M , D } ) when ( D > 30 andalso (
M =:= 4 orelse
M =:= 6 orelse
M =:= 9 orelse
M =:= 11 ) ) - >
fmid ( { Y , M + 1 , D - 30 } ) ;
fmid ( { Y , M , D } ) when M =:= 2 andalso D > 29 andalso ? IS_LEAP_YEAR ( Y ) - >
fmid ( { Y , M + 1 , D - 29 } ) ;
fmid ( { Y , M , D } ) when M =:= 2 andalso D > 28 andalso not ( ? IS_LEAP_YEAR ( Y ) ) - >
fmid ( { Y , M + 1 , D - 28 } ) ;
fmid ( { Y , M , D } ) when D > 31 - >
fmid ( { Y , M + 1 , D - 31 } ) ;
fmid ( { Y , M , D } ) when D < 1 - >
TargetMonth = case M - 1 of
0 - > 12 ;
X - > X
end ,
DaysInTargetMonth = calendar : last_day_of_the_month ( Y , TargetMonth ) ,
fmid ( { Y , M - 1 , D + DaysInTargetMonth } ) ;
fmid ( Date ) - >
Date .
2015-11-06 17:03:16 -06:00
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Ranges %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
range ( seconds , Interval , Start , Finish ) - >
range_inner ( fun add_seconds / 2 , Interval , Start , Finish ) ;
range ( minutes , Interval , Start , Finish ) - >
range_inner ( fun add_minutes / 2 , Interval , Start , Finish ) ;
range ( hours , Interval , Start , Finish ) - >
range_inner ( fun add_hours / 2 , Interval , Start , Finish ) ;
range ( days , Interval , Start , Finish ) - >
range_inner ( fun add_days / 2 , Interval , Start , Finish ) ;
range ( weeks , Interval , Start , Finish ) - >
range_inner ( fun add_weeks / 2 , Interval , Start , Finish ) ;
range ( months , Interval , Start , Finish ) - >
range_inner ( fun add_months / 2 , Interval , Start , Finish ) ;
range ( years , Interval , Start , Finish ) - >
range_inner ( fun add_years / 2 , Interval , Start , Finish ) .
range_inner ( IntervalFun , Interval , Start , Finish ) when Interval > 0 - >
%% If Interval>0, then we're ascending, and we want to compare start/end
%% dates normally
CompareFun = fun ( S , F ) - > compare ( S , F ) end ,
range_normalizer ( IntervalFun , Interval , CompareFun , Start , Finish ) ;
range_inner ( IntervalFun , Interval , Start , Finish ) when Interval < 0 - >
%% If Interval<0, then we're descending, and we want to compare start/end
%% dates backwards (we want to end when the Start Date is Lower than
%% Finish)
CompareFun = fun ( S , F ) - > compare ( F , S ) end ,
range_normalizer ( IntervalFun , Interval , CompareFun , Start , Finish ) ;
range_inner ( _ , Interval , _ , _ ) when Interval == 0 - >
throw ( interval_cannot_be_zero ) .
range_normalizer ( IntervalFun , Interval , CompareFun , Start0 , Finish0 ) - >
%% Convert dates to unixtime for speed's sake
Start = to_unixtime ( Start0 ) ,
Finish = to_unixtime ( Finish0 ) ,
%% Prepare the incrementer, so we just need to pass the date to the incrementer.
Incrementer = fun ( D ) - > IntervalFun ( Interval , D ) end ,
range_worker ( Incrementer , CompareFun , Start , Finish ) .
range_worker ( Incrementer , CompareFun , Start , Finish ) - >
case CompareFun ( Start , Finish ) of
0 - > [ Finish ] ; %% Equal, so we add our Finish value
1 - > [ ] ; %% Start is after Finish, so we add nothing
- 1 - > %% Start is before Finish, so we include it, and recurse
NextDay = Incrementer ( Start ) ,
[ Start | range_worker ( Incrementer , CompareFun , NextDay , Finish ) ]
end .
range_seconds ( Interval , Start , Finish ) - >
range ( seconds , Interval , Start , Finish ) .
range_minutes ( Interval , Start , Finish ) - >
range ( minutes , Interval , Start , Finish ) .
range_hours ( Interval , Start , Finish ) - >
range ( hours , Interval , Start , Finish ) .
range_days ( Interval , Start , Finish ) - >
range ( days , Interval , Start , Finish ) .
range_weeks ( Interval , Start , Finish ) - >
range ( weeks , Interval , Start , Finish ) .
range_months ( Interval , Start , Finish ) - >
range ( months , Interval , Start , Finish ) .
range_years ( Interval , Start , Finish ) - >
range ( years , Interval , Start , Finish ) .
2014-08-22 23:47:39 -05:00
2016-03-05 15:16:03 -06:00
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%% Relative Date Parsing %%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
parse_relative ( { relative , Date , Relation } ) when is_atom ( Relation ) - >
parse_relative ( { relative , Date , atom_to_list ( Relation ) } ) ;
2016-03-05 16:26:58 -06:00
parse_relative ( { relative , Date , Relation } ) when is_list ( Relation ) ; is_binary ( Relation ) - >
2016-03-07 05:48:56 +00:00
case parse_actual_relation ( Relation ) of
undefined - > undefined ;
{ OpStr , NumStr , UnitStr } - >
{ Num , Unit } = normalize_relative_matches ( OpStr , NumStr , UnitStr ) ,
add_unit ( Unit , Num , Date )
end ;
2016-03-05 15:16:03 -06:00
parse_relative ( now ) - >
unixtime ( ) ;
parse_relative ( " now " ) - >
unixtime ( ) ;
parse_relative ( < < " now " > > ) - >
unixtime ( ) ;
2016-03-05 16:26:58 -06:00
parse_relative ( Relation ) when is_list ( Relation ) ; is_binary ( Relation ) - >
parse_relative ( { relative , unixtime ( ) , Relation } ) ;
parse_relative ( _ ) - >
undefined .
2016-03-05 15:16:03 -06:00
%% I would do this function recursively, but the return order of arguments
%% inconsistent, so I just leave it like this. It's a little nasty to have the
%% nested case expressions, but I can deal with it.
parse_actual_relation ( Relation ) - >
PrefixRE = " ^( \\ -| \\ +|in) \\ s?( \\ d+) (second|minute|hour|day|week|month|year)s?$ " ,
2016-04-13 19:39:30 -05:00
SuffixRE = " ^( \\ d+) (second|minute|hour|day|week|month|year)s? \\ s?(ago|from now)?$ " ,
2016-03-05 15:16:03 -06:00
case re : run ( Relation , PrefixRE , [ { capture , all_but_first , list } ] ) of
nomatch - >
case re : run ( Relation , SuffixRE , [ { capture , all_but_first , list } ] ) of
nomatch - > undefined ;
{ match , [ NumStr , UnitStr , OpStr ] } - >
{ OpStr , NumStr , UnitStr }
end ;
{ match , [ OpStr , NumStr , UnitStr ] } - >
{ OpStr , NumStr , UnitStr }
end .
normalize_relative_matches ( OpStr , NumStr , UnitStr ) - >
Op = normalize_relative_op ( OpStr ) ,
Num = list_to_integer ( Op ++ NumStr ) ,
Unit = list_to_existing_atom ( UnitStr ) ,
{ Num , Unit } .
normalize_relative_op ( Op ) - >
case Op of
" + " - > " + " ;
" - " - > " - " ;
" ago " - > " - " ;
" from now " - > " + " ;
" in " - > " + "
end .
2013-09-12 20:14:49 -05:00
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Timezone Stuff %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2013-10-22 17:29:16 -05:00
get_timezone_shift ( TZ , Disambiguate , Date ) - >
2013-09-12 20:14:49 -05:00
case localtime : tz_shift ( Date , TZ ) of
unable_to_detect - > { error , unable_to_detect } ;
{ error , T } - > { error , T } ;
2013-10-22 17:29:16 -05:00
{ Sh , _ } when Disambiguate == prefer_standard - > Sh ;
{ _ , Sh } when Disambiguate == prefer_daylight - > Sh ;
2013-09-12 20:14:49 -05:00
Sh - > Sh
end .
2013-04-22 23:46:23 -05:00
2013-02-21 22:43:02 -06:00
extract_timezone ( Unixtime ) when is_integer ( Unixtime ) - >
2013-04-24 01:07:16 -05:00
{ Unixtime , " GMT " } ;
2013-02-21 22:43:02 -06:00
extract_timezone ( DateString ) when is_list ( DateString ) - >
2013-04-24 01:07:16 -05:00
case extract_gmt_relative_timezone ( DateString ) of
undefined - >
AllTimezones = localtime : list_timezones ( ) ,
RevDate = lists : reverse ( DateString ) ,
extract_timezone_helper ( RevDate , AllTimezones ) ;
{ Date , GMTRel } - >
{ Date , GMTRel }
end ;
2013-02-21 22:43:02 -06:00
extract_timezone ( Date = { { _ , _ , _ } , { _ , _ , _ } } ) - >
2013-04-24 01:07:16 -05:00
{ Date , ? DETERMINE_TZ } ;
2016-03-05 15:16:03 -06:00
extract_timezone ( Rel = { relative , _ , _ } ) - >
{ Rel , " GMT " } ;
2013-02-21 22:43:02 -06:00
extract_timezone ( Now = { _ , _ , _ } ) - >
2013-04-24 01:07:16 -05:00
{ Now , " GMT " } ;
2013-02-21 22:43:02 -06:00
extract_timezone ( { MiscDate , TZ } ) - >
2013-04-24 01:07:16 -05:00
{ MiscDate , TZ } .
2013-04-22 23:46:23 -05:00
extract_gmt_relative_timezone ( DateString ) - >
2013-04-24 01:07:16 -05:00
RE = " ^(.*?)(?:GMT|UTC)?([+-])( \\ d{1,2}):?( \\ d{2})?$ " ,
case re : run ( DateString , RE , [ { capture , all_but_first , list } , caseless ] ) of
{ match , [ NewDateStr , Sign , HourStr , MinStr ] } - >
{ NewDateStr , minutes_from_gmt_relative_timezone ( Sign , HourStr , MinStr ) } ;
{ match , [ NewDateStr , Sign , HourStr ] } - >
{ NewDateStr , minutes_from_gmt_relative_timezone ( Sign , HourStr , " 0 " ) } ;
nomatch - >
undefined
end .
2013-04-22 23:46:23 -05:00
%% The number of minutes a the timezone is behind gmt
minutes_from_gmt_relative_timezone ( " + " , HourStr , MinStr ) - >
2013-04-24 01:07:16 -05:00
- minutes_from_gmt_relative_timezone ( " - " , HourStr , MinStr ) ;
2013-04-22 23:46:23 -05:00
minutes_from_gmt_relative_timezone ( " - " , HourStr , MinStr ) - >
2013-04-24 01:07:16 -05:00
list_to_integer ( HourStr ) * 60 + list_to_integer ( MinStr ) .
2013-04-22 23:46:23 -05:00
2013-02-21 22:43:02 -06:00
extract_timezone_helper ( RevDate , [ ] ) - >
2013-04-24 01:07:16 -05:00
{ lists : reverse ( RevDate ) , ? DETERMINE_TZ } ;
2013-04-29 22:16:31 -05:00
extract_timezone_helper ( RevDate , [ TZ | TZs ] ) when length ( RevDate ) > = length ( TZ ) - >
2013-04-24 01:07:16 -05:00
RevTZ = lists : reverse ( TZ ) ,
case lists : split ( length ( TZ ) , RevDate ) of
{ RevTZ , " " ++ Remainder } - >
{ lists : reverse ( Remainder ) , TZ } ;
_ - >
extract_timezone_helper ( RevDate , TZs )
2013-04-29 22:16:31 -05:00
end ;
extract_timezone_helper ( RevDate , [ _ TZ | TZs ] ) - >
extract_timezone_helper ( RevDate , TZs ) .
2013-01-14 13:58:12 -06:00
2016-05-31 18:45:54 -05:00
%% This is the timezone only if the qdate application variable
%% "default_timezone" isn't set or is set to undefined.
%% It's recommended that your app sets the var in a config, or at least using
%%
%% application:set_env(qdate, default_timezone, "GMT").
%%
default_timezone ( ) - >
case application : get_env ( qdate , default_timezone ) of
undefined - > " GMT " ;
{ ok , { Mod , Fun } } - > Mod : Fun ( ) ;
{ ok , TZ } - > TZ
end .
2013-03-25 11:52:14 -05:00
determine_timezone ( ) - >
2013-04-24 01:07:16 -05:00
case qdate_srv : get_timezone ( ) of
2016-05-31 18:45:54 -05:00
undefined - > default_timezone ( ) ;
2013-04-24 01:07:16 -05:00
TZ - > TZ
end .
2013-03-25 11:52:14 -05:00
2013-04-23 22:10:28 -05:00
%% If FromTZ is an integer, then it's an integer that represents the number of minutes
%% relative to GMT. So we convert the date to GMT based on that number, then we can
%% do the other timezone conversion.
2013-10-22 17:29:16 -05:00
date_tz_to_tz ( Date , Disambiguate , FromTZ , ToTZ ) when is_integer ( FromTZ ) - >
2013-04-24 01:07:16 -05:00
NewDate = localtime : adjust_datetime ( Date , FromTZ ) ,
2013-10-22 17:29:16 -05:00
date_tz_to_tz ( NewDate , Disambiguate , " GMT " , ToTZ ) ;
date_tz_to_tz ( Date , Disambiguate , FromTZ , ToTZ ) - >
2013-04-24 01:07:16 -05:00
ActualToTZ = ensure_timezone ( ToTZ ) ,
2013-10-22 17:29:16 -05:00
case Disambiguate of
prefer_standard - >
localtime : local_to_local ( Date , FromTZ , ActualToTZ ) ;
prefer_daylight - >
localtime : local_to_local_dst ( Date , FromTZ , ActualToTZ ) ;
both - >
date_tz_to_tz_both ( Date , FromTZ , ToTZ )
end .
date_tz_to_tz_both ( Date , FromTZ , ToTZ ) - >
Standard = localtime : local_to_local ( Date , FromTZ , ToTZ ) ,
Daylight = localtime : local_to_local_dst ( Date , FromTZ , ToTZ ) ,
if
Standard =:= Daylight - >
Standard ;
? else - >
{ ambiguous , Standard , Daylight }
end .
2013-04-23 22:10:28 -05:00
2013-09-18 11:15:59 -05:00
set_timezone ( TZ ) when is_binary ( TZ ) - >
set_timezone ( binary_to_list ( TZ ) ) ;
2013-04-23 22:10:28 -05:00
set_timezone ( TZ ) - >
2013-04-24 01:07:16 -05:00
qdate_srv : set_timezone ( TZ ) .
2013-04-23 22:10:28 -05:00
2013-09-18 11:15:59 -05:00
set_timezone ( Key , TZ ) when is_binary ( TZ ) - >
set_timezone ( Key , binary_to_list ( TZ ) ) ;
2013-04-23 22:10:28 -05:00
set_timezone ( Key , TZ ) - >
2013-04-24 01:07:16 -05:00
qdate_srv : set_timezone ( Key , TZ ) .
2013-04-23 22:10:28 -05:00
get_timezone ( ) - >
2016-04-14 11:20:50 -05:00
? DETERMINE_TZ .
2013-04-23 22:10:28 -05:00
get_timezone ( Key ) - >
2013-04-24 01:07:16 -05:00
qdate_srv : get_timezone ( Key ) .
2013-04-23 22:10:28 -05:00
2014-08-23 00:31:22 -05:00
ensure_timezone ( auto ) - >
? DETERMINE_TZ ;
ensure_timezone ( Key ) when is_atom ( Key ) orelse is_tuple ( Key ) - >
case get_timezone ( Key ) of
undefined - > throw ( { timezone_key_not_found , Key } ) ;
ToTZ - > ToTZ
end ;
ensure_timezone ( TZ ) when is_binary ( TZ ) - >
binary_to_list ( TZ ) ;
ensure_timezone ( TZ ) when is_list ( TZ ) - >
TZ .
2013-04-23 23:16:26 -05:00
2013-04-23 22:10:28 -05:00
clear_timezone ( ) - >
2013-04-24 01:07:16 -05:00
qdate_srv : clear_timezone ( ) .
2013-04-23 22:10:28 -05:00
clear_timezone ( Key ) - >
2013-04-24 01:07:16 -05:00
qdate_srv : clear_timezone ( Key ) .
2013-04-23 22:10:28 -05:00
2013-09-12 20:14:49 -05:00
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Register Parsers %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2013-01-14 13:58:12 -06:00
2014-08-30 15:53:19 -05:00
get_parsers ( ) - >
qdate_srv : get_parsers ( ) .
2013-03-26 01:46:33 -05:00
register_parser ( Key , Parser ) when is_function ( Parser , 1 ) - >
2013-04-24 01:07:16 -05:00
qdate_srv : register_parser ( Key , Parser ) .
2013-03-26 01:46:33 -05:00
register_parser ( Parser ) when is_function ( Parser , 1 ) - >
2013-04-24 01:07:16 -05:00
qdate_srv : register_parser ( Parser ) .
2013-03-26 01:46:33 -05:00
deregister_parser ( Key ) - >
2013-04-24 01:07:16 -05:00
qdate_srv : deregister_parser ( Key ) .
2013-03-26 01:46:33 -05:00
deregister_parsers ( ) - >
2013-04-24 01:07:16 -05:00
qdate_srv : deregister_parsers ( ) .
2013-03-26 01:46:33 -05:00
2013-09-12 20:14:49 -05:00
try_registered_parsers ( RawDate ) - >
Parsers = qdate_srv : get_parsers ( ) ,
try_parsers ( RawDate , Parsers ) .
try_parsers ( _ RawDate , [ ] ) - >
undefined ;
try_parsers ( RawDate , [ { ParserKey , Parser } | Parsers ] ) - >
try Parser ( RawDate ) of
2016-03-05 13:52:02 -06:00
Timestamp when is_integer ( Timestamp ) - >
2016-04-11 18:12:35 -05:00
{ Timestamp , " GMT " } ;
2013-09-12 20:14:49 -05:00
{ { _ , _ , _ } , { _ , _ , _ } } = DateTime - >
{ DateTime , undefined } ;
{ DateTime = { { _ , _ , _ } , { _ , _ , _ } } , Timezone } - >
{ DateTime , Timezone } ;
undefined - >
try_parsers ( RawDate , Parsers ) ;
Other - >
throw ( { invalid_parser_return_value , [ { parser_key , ParserKey } , { return , Other } ] } )
catch
Error : Reason - >
2016-03-05 16:26:58 -06:00
Stacktrace = erlang : get_stacktrace ( ) ,
throw ( { error_in_parser , [ { error , { Error , Reason } } , { parser_key , ParserKey } , { stacktrace , Stacktrace } ] } )
2013-09-12 20:14:49 -05:00
end .
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Register Formats %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2014-08-30 15:53:19 -05:00
get_formats ( ) - >
qdate_srv : get_formats ( ) .
2013-03-26 01:46:33 -05:00
register_format ( Key , Format ) - >
2013-04-24 01:07:16 -05:00
qdate_srv : register_format ( Key , Format ) .
2013-03-26 01:46:33 -05:00
deregister_format ( Key ) - >
2013-04-24 01:07:16 -05:00
qdate_srv : deregister_format ( Key ) .
2013-03-26 01:46:33 -05:00
2013-09-12 20:14:49 -05:00
2013-01-14 13:58:12 -06:00
unixtime_to_now ( T ) when is_integer ( T ) - >
2013-04-24 01:07:16 -05:00
MegaSec = floor ( T / 1000000 ) ,
Secs = T - MegaSec * 1000000 ,
{ MegaSec , Secs , 0 } .
2013-01-14 13:58:12 -06:00
unixtime_to_date ( T ) - >
2013-04-24 01:07:16 -05:00
Now = unixtime_to_now ( T ) ,
calendar : now_to_datetime ( Now ) .
2013-01-14 13:58:12 -06:00
floor ( N ) when N > = 0 - >
2013-04-24 01:07:16 -05:00
trunc ( N ) ;
2013-01-14 13:58:12 -06:00
floor ( N ) when N < 0 - >
2013-04-24 01:07:16 -05:00
Int = trunc ( N ) ,
if
Int == N - > Int ;
true - > Int - 1
end .
2013-03-25 15:21:05 -05:00
2013-09-12 20:14:49 -05:00
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% TESTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2013-03-26 01:46:33 -05:00
2013-02-21 22:43:02 -06:00
- include_lib ( " eunit/include/eunit.hrl " ) .
2013-03-25 11:52:14 -05:00
%% emulates as if a forum-type website has a Site tz, and a user-specified tz
- define ( SITE_TZ , " PST " ) .
2013-09-18 11:15:59 -05:00
- define ( USER_TZ , < < " CST " > > ) .
2013-03-25 11:52:14 -05:00
- define ( SELF_TZ , " EST " ) . %% Self will be the pid of the current running process
- define ( SITE_KEY , test_site_key ) .
- define ( USER_KEY , test_user_key ) .
tz_test_ ( ) - >
2013-04-24 01:07:16 -05:00
{
setup ,
fun start_test / 0 ,
fun stop_test / 1 ,
fun ( SetupData ) - >
{ inorder , [
simple_test ( SetupData ) ,
2013-09-12 20:14:49 -05:00
compare_test ( SetupData ) ,
2013-04-24 01:07:16 -05:00
tz_tests ( SetupData ) ,
2013-04-29 22:16:31 -05:00
parser_format_test ( SetupData ) ,
2013-10-22 17:29:16 -05:00
test_deterministic_parser ( SetupData ) ,
2014-08-23 00:29:59 -05:00
test_disambiguation ( SetupData ) ,
arith_tests ( SetupData )
2013-04-24 01:07:16 -05:00
] }
end
} .
2013-03-25 11:52:14 -05:00
2013-04-29 22:16:31 -05:00
test_deterministic_parser ( _ ) - >
{ inorder , [
? _ assertEqual ( ok , application : set_env ( qdate , deterministic_parsing , { now , now } ) ) ,
? _ assertEqual ( { date ( ) , { 7 , 0 , 0 } } , qdate : to_date ( " 7am " ) ) ,
? _ assertEqual ( { { 2012 , 5 , 10 } , time ( ) } , qdate : to_date ( " 2012-5-10 " ) ) ,
? _ assertEqual ( ok , application : set_env ( qdate , deterministic_parsing , { zero , zero } ) ) ,
? _ assertEqual ( { { 1970 , 1 , 1 } , { 7 , 0 , 0 } } , qdate : to_date ( " 7am " ) ) ,
? _ assertEqual ( { { 2012 , 5 , 10 } , { 0 , 0 , 0 } } , qdate : to_date ( " 2012-5-10 " ) ) ,
? _ assertEqual ( ok , application : unset_env ( qdate , deterministic_parsing ) ) ,
? _ assertEqual ( { { 1970 , 1 , 1 } , { 7 , 0 , 0 } } , qdate : to_date ( " 7am " ) ) ,
? _ assertEqual ( { { 2012 , 5 , 10 } , { 0 , 0 , 0 } } , qdate : to_date ( " 2012-5-10 " ) )
] } .
2013-10-22 17:29:16 -05:00
test_disambiguation ( _ ) - >
{ inorder , [
? _ assertEqual ( ok , set_timezone ( " America/New York " ) ) ,
? _ assertEqual ( { ambiguous , { { 2013 , 11 , 3 } , { 6 , 0 , 0 } } , { { 2013 , 11 , 3 } , { 5 , 0 , 0 } } } , qdate : to_date ( " GMT " , both , { { 2013 , 11 , 3 } , { 1 , 0 , 0 } } ) ) ,
? _ assertEqual ( { { 2013 , 11 , 3 } , { 6 , 0 , 0 } } , qdate : to_date ( " GMT " , prefer_standard , { { 2013 , 11 , 3 } , { 1 , 0 , 0 } } ) ) ,
? _ assertEqual ( { { 2013 , 11 , 3 } , { 5 , 0 , 0 } } , qdate : to_date ( " GMT " , prefer_daylight , { { 2013 , 11 , 3 } , { 1 , 0 , 0 } } ) ) ,
? _ assertEqual ( { ambiguous , " GMT " , " GMT " } , qdate : to_string ( " T " , " GMT " , both , { { 2013 , 11 , 3 } , { 1 , 0 , 0 } } ) ) ,
? _ assertEqual ( { ambiguous , " EST " , " EDT " } , qdate : to_string ( " T " , auto , both , { { 2013 , 11 , 3 } , { 1 , 0 , 0 } } ) ) ,
? _ assertEqual ( ok , set_timezone ( " GMT " ) ) ,
? _ assertEqual ( { ambiguous , { { 2013 , 11 , 3 } , { 1 , 0 , 0 } } , { { 2013 , 11 , 3 } , { 2 , 0 , 0 } } } , qdate : to_date ( " America/New York " , both , { { 2013 , 11 , 3 } , { 6 , 0 , 0 } } ) ) ,
? _ assertEqual ( { { 2013 , 11 , 3 } , { 2 , 0 , 0 } } , qdate : to_date ( " America/New York " , prefer_daylight , { { 2013 , 11 , 3 } , { 6 , 0 , 0 } } ) ) ,
? _ assertEqual ( { { 2013 , 11 , 3 } , { 1 , 0 , 0 } } , qdate : to_date ( " America/New York " , prefer_standard , { { 2013 , 11 , 3 } , { 6 , 0 , 0 } } ) )
] } .
2013-03-25 11:52:14 -05:00
tz_tests ( _ ) - >
2013-04-24 01:07:16 -05:00
{ inorder , [
2013-09-18 11:15:59 -05:00
? _ assertEqual ( ok , set_timezone ( < < " Europe/Moscow " > > ) ) ,
? _ assertEqual ( " Europe/Moscow " , get_timezone ( ) ) ,
2013-04-24 01:07:16 -05:00
? _ assertEqual ( ok , set_timezone ( ? SELF_TZ ) ) ,
? _ assertEqual ( ? SELF_TZ , get_timezone ( ) ) ,
2013-09-18 11:15:59 -05:00
? _ assertEqual ( " CST " , get_timezone ( ? USER_KEY ) ) ,
2013-04-24 01:07:16 -05:00
? _ assertEqual ( ? SITE_TZ , get_timezone ( ? SITE_KEY ) ) ,
2013-04-29 18:55:36 -05:00
? _ assertEqual ( { { 2013 , 3 , 7 } , { 0 , 0 , 0 } } , to_date ( ? USER_KEY , " 3/7/2013 1:00am EST " ) ) ,
? _ assertEqual ( { { 2013 , 3 , 7 } , { 0 , 0 , 0 } } , to_date ( ? SITE_KEY , " 3/7/2013 3:00am EST " ) ) ,
2013-04-24 01:07:16 -05:00
? _ assertEqual ( { { 2013 , 3 , 7 } , { 2 , 0 , 0 } } , to_date ( " 3/7/2013 1:00am CST " ) ) , %% will use the current pid's setting
? _ assertEqual ( " America/Chicago " , to_string ( " e " , " America/Chicago " , " 3/7/2013 1:00am " ) ) ,
? _ assertEqual ( " -0500 " , to_string ( " O " , " EST " , " 3/7/2013 1:00am CST " ) ) ,
? _ assertEqual ( " -05:00 " , to_string ( " P " , " EST " , " 3/7/2013 1:00am CST " ) ) ,
? _ assertEqual ( " EST " , to_string ( " T " , " America/New York " , " 3/7/2013 1:00am CST " ) ) ,
? _ assertEqual ( ? SITE_TZ , to_string ( " T " , ? SITE_KEY , " 3/7/2013 1:00am CST " ) ) ,
? _ assertEqual ( integer_to_list ( - 5 * 3600 ) , to_string ( " Z " , " EST " , " 3/7/2013 1:00am CST " ) ) ,
? _ assertEqual ( " Thu, 07 Mar 2013 13:15:00 -0500 " , to_string ( " r " , " EST " , " 3/7/2013 1:15:00pm " ) ) ,
? _ assertEqual ( " 2013-03-07T13:15:00-05:00 " , to_string ( " c " , " EST " , " 3/7/2013 1:15:00pm " ) ) ,
2013-04-29 18:55:36 -05:00
? _ assertEqual ( { { 2013 , 3 , 7 } , { 6 , 0 , 0 } } , to_date ( " GMT " , " 3/7/2013 12:00am -0600 " ) ) ,
? _ assertEqual ( { { 2013 , 3 , 7 } , { 6 , 0 , 0 } } , to_date ( " GMT " , " 3/7/2013 12:00am -600 " ) ) ,
? _ assertEqual ( { { 2013 , 3 , 7 } , { 6 , 0 , 0 } } , to_date ( " GMT " , " 3/7/2013 12:00am GMT-0600 " ) ) ,
? _ assertEqual ( { { 2013 , 3 , 7 } , { 6 , 0 , 0 } } , to_date ( " GMT " , " 3/7/2013 12:00am utc-0600 " ) ) ,
? _ assertEqual ( { { 2013 , 3 , 7 } , { 1 , 0 , 0 } } , to_date ( " EST " , " 3/7/2013 12:00am utc-0600 " ) ) ,
? _ assertEqual ( { { 2013 , 3 , 6 } , { 18 , 0 , 0 } } , to_date ( " GMT " , " 3/7/2013 12:00am +0600 " ) ) ,
? _ assertEqual ( { { 2013 , 3 , 6 } , { 12 , 0 , 0 } } , to_date ( " CST " , " 3/7/2013 12:00am +0600 " ) ) ,
2013-04-24 01:07:16 -05:00
2016-01-31 09:07:54 -06:00
%% These next two test check to make sure that the tz database properly
%% interprets GMT+/-X timezones (an earlier issue with
%% erlang_localtime's tz database had it incrementing/decrementing the
%% minute field rather than hours.
%%
%% It also ensures that GMT+/-X handling is interpreted the way you'd
%% intuitively expect, rather than the POSIX way, which is, quite
%% frankly, broken.
? _ assertEqual ( { { 2013 , 3 , 7 } , { 10 , 0 , 0 } } , to_date ( " GMT-0 " , " 3/7/2013 10:00am GMT " ) ) ,
? _ assertEqual ( { { 2013 , 3 , 7 } , { 10 , 0 , 0 } } , to_date ( " GMT+0 " , " 3/7/2013 10:00am GMT " ) ) ,
? _ assertEqual ( { { 2013 , 3 , 7 } , { 9 , 0 , 0 } } , to_date ( " GMT-1 " , " 3/7/2013 10:00am GMT " ) ) ,
? _ assertEqual ( { { 2013 , 3 , 7 } , { 11 , 0 , 0 } } , to_date ( " GMT+1 " , " 3/7/2013 10:00am GMT " ) ) ,
2013-04-24 01:07:16 -05:00
%% parsing, then reformatting the same time with a different timezone using the php "r" (rfc2822)
? _ assertEqual ( " Thu, 07 Mar 2013 12:15:00 -0600 " ,
to_string ( " r " , " CST " , to_string ( " r " , " EST " , { { 2013 , 3 , 7 } , { 13 , 15 , 0 } } ) ) ) ,
%% A bunch of unixtime and now tests with timezones
? _ assertEqual ( " 1987-08-10 00:59:15 GMT " , to_string ( " Y-m-d H:i:s T " , " GMT " , 555555555 ) ) ,
? _ assertEqual ( " 1987-08-09 19:59:15 CDT " , to_string ( " Y-m-d H:i:s T " , " CDT " , 555555555 ) ) ,
? _ assertEqual ( " 1987-08-09 20:59:15 EDT " , to_string ( " Y-m-d H:i:s T " , " America/New York " , 555555555 ) ) ,
? _ assertEqual ( ok , set_timezone ( " GMT " ) ) ,
? _ assertEqual ( 555555555 , to_unixtime ( " 1987-08-10 00:59:15 GMT " ) ) ,
2013-04-23 22:10:28 -05:00
? _ assertEqual ( { 555 , 555555 , 0 } , to_now ( " 1987-08-10 00:59:15 GMT " ) ) ,
2013-04-24 01:07:16 -05:00
? _ assertEqual ( ok , set_timezone ( " EST " ) ) ,
? _ assertEqual ( 555555555 , to_unixtime ( " 1987-08-10 00:59:15 GMT " ) ) ,
2013-04-23 22:10:28 -05:00
? _ assertEqual ( { 555 , 555555 , 0 } , to_now ( " 1987-08-10 00:59:15 GMT " ) ) ,
2015-10-14 16:13:42 +02:00
? _ assertEqual ( ok , set_timezone ( " GMT " ) ) ,
2016-03-01 00:11:11 -06:00
? _ assertEqual ( { { 1970 , 1 , 1 } , { 1 , 0 , 0 } } , to_date ( " CET " , " 1970-01-01T00:00:00Z " ) ) ,
? _ assertEqual ( ok , set_timezone ( " UTC " ) ) ,
2016-04-13 19:38:04 -05:00
? _ assertEqual ( 1521945120 , to_unixtime ( " 2018-3-25T2:32:00 " ) ) ,
? _ assertEqual ( true , between ( " -1 seconds " , os : timestamp ( ) , " +1 seconds " ) ) ,
? _ assertEqual ( true , between ( " 60 hours ago " , unixtime ( ) , " in 15 days " ) ) ,
? _ assertEqual ( false , between ( " +1 seconds " , qdate : to_string ( " n/j/Y g:ia " ) , " +2 seconds " ) ) ,
? _ assertEqual ( false , between ( " 5 seconds ago " , " 1 second ago " ) )
2013-04-24 01:07:16 -05:00
] } .
2013-03-25 16:43:27 -05:00
2013-04-23 22:10:28 -05:00
2013-03-25 16:43:27 -05:00
simple_test ( _ ) - >
2013-04-24 01:07:16 -05:00
{ inorder , [
? _ assertEqual ( ok , clear_timezone ( ) ) ,
? _ assertEqual ( 0 , to_unixtime ( { 0 , 0 , 0 } ) ) ,
? _ assertEqual ( { 0 , 0 , 0 } , to_now ( 0 ) ) ,
? _ assertEqual ( 0 , to_unixtime ( " 1970-01-01 12:00am GMT " ) ) ,
? _ assertEqual ( 21600 , to_unixtime ( " 1970-01-01 12:00am CST " ) ) ,
? _ assertEqual ( 0 , to_unixtime ( { { 1970 , 1 , 1 } , { 0 , 0 , 0 } } ) ) ,
? _ assertEqual ( { { 1970 , 1 , 1 } , { 0 , 0 , 0 } } , to_date ( 0 ) ) ,
? _ assertEqual ( { { 2013 , 3 , 7 } , { 0 , 0 , 0 } } , to_date ( to_unixtime ( " 2013-03-07 12am " ) ) ) ,
? _ assertEqual ( " 2013-12-21 12:24pm " , to_string ( " Y-m-d g:ia " , { { 2013 , 12 , 21 } , { 12 , 24 , 21 } } ) ) ,
? _ assertEqual ( " 2012-12-01 1:00pm " , to_string ( " Y-m-d g:ia " , " EST " , " 2012-12-01 12:00pm CST " ) ) ,
? _ assertEqual ( < < " 2012-12-01 1:00pm " > > , to_string ( < < " Y-m-d g:ia " > > , " EST " , " 2012-12-01 12:00pm CST " ) ) ,
? _ assertEqual ( < < " 2012-12-01 1:00pm " > > , to_string ( < < " Y-m-d g:ia " > > , " EST " , < < " 2012-12-01 12:00pm CST " > > ) ) ,
? _ assertEqual ( " 2012-12-01 1:00pm " , to_string ( " Y-m-d g:ia " , " EST " , < < " 2012-12-01 12:00pm CST " > > ) ) ,
2013-04-29 18:55:36 -05:00
? _ assertEqual ( " 2012-12-01 1:00pm " , to_string ( " Y-m-d g:ia " , < < " EST " > > , < < " 2012-12-01 12:00pm CST " > > ) ) ,
2013-04-24 01:07:16 -05:00
? _ assertEqual ( to_unixtime ( " 2012-01-01 12:00pm CST " ) , to_unixtime ( " 2012-01-01 10:00am PST " ) ) ,
? _ assertEqual ( { { 2012 , 12 , 31 } , { 18 , 15 , 15 } } , to_date ( " Dec 31, 2012 6:15:15pm " ) ) ,
2013-04-29 18:55:36 -05:00
? _ assertEqual ( { { 2013 , 1 , 1 } , { 0 , 15 , 15 } } , to_date ( " GMT " , " December 31, 2012 6:15:15pm CST " ) )
2013-04-24 01:07:16 -05:00
] } .
2013-02-21 22:43:02 -06:00
2013-09-12 20:14:49 -05:00
compare_test ( _ ) - >
{ inorder , [
? _ assertEqual ( true , compare ( { { 2013 , 9 , 10 } , { 0 , 0 , 0 } } , '=' , " Sep 10th, 2013 12:00am " ) ) ,
2014-03-11 22:41:17 -05:00
? _ assertEqual ( true , compare ( " 9/10/2013 1am EDT " , '==' , " Sep 10th, 2013 12:00:00am CDT " ) ) ,
2013-09-12 20:14:49 -05:00
? _ assertEqual ( true , compare ( { { 2013 , 9 , 10 } , { 0 , 0 , 0 } } , '=<' , " Sep 10th, 2013 12:00am " ) ) ,
? _ assertEqual ( false , compare ( { { 2013 , 9 , 10 } , { 0 , 0 , 1 } } , '=' , " Sep 10th, 2013 12:00am " ) ) ,
? _ assertEqual ( true , compare ( { { 2013 , 9 , 10 } , { 0 , 0 , 1 } } , '=/=' , " Sep 10th, 2013 12:00am " ) ) ,
? _ assertEqual ( true , compare ( { { 2013 , 9 , 10 } , { 0 , 0 , 1 } } , '>' , " Sep 10th, 2013 12:00am " ) ) ,
? _ assertEqual ( false , compare ( { { 2013 , 9 , 10 } , { 0 , 0 , 1 } } , '<' , " Sep 10th, 2013 12:00am " ) ) ,
? _ assertEqual ( true , compare ( { { 2013 , 9 , 10 } , { 0 , 0 , 1 } } , '<' , " Sep 10th, 2013 12:00:02am " ) ) ,
? _ assertEqual ( true , compare ( { { 2013 , 9 , 10 } , { 0 , 0 , 1 } } , '<' , " Sep 10th, 2013 12:02am " ) ) ,
? _ assertEqual ( true , compare ( { { 2013 , 9 , 10 } , { 0 , 0 , 1 } } , '<' , " Sep 10th, 2013 1am " ) ) ,
? _ assertEqual ( true , compare ( { { 2013 , 9 , 9 } , { 23 , 59 , 59 } } , '<' , " Sep 10th, 2013 12am " ) ) ,
2013-09-12 20:27:08 -05:00
? _ assertEqual ( false , compare ( { { 2013 , 9 , 9 } , { 23 , 59 , 59 } } , '>' , " Sep 10th, 2013 12am " ) ) ,
? _ assertEqual ( true , compare ( " 11am EST " , '==' , " 10am CST " ) )
2013-09-12 20:14:49 -05:00
] } .
2013-03-26 01:46:33 -05:00
parser_format_test ( _ ) - >
2013-04-24 01:07:16 -05:00
{ inorder , [
? _ assertEqual ( { { 2008 , 2 , 8 } , { 0 , 0 , 0 } } , to_date ( " 20080208 " ) ) ,
? _ assertThrow ( { ec_date , { bad_date , _ } } , to_date ( " 20111232 " ) ) , %% invalid_date with custom format
? _ assertEqual ( " 2/8/2008 " , to_string ( shortdate , { { 2008 , 2 , 8 } , { 0 , 0 , 0 } } ) ) ,
? _ assertEqual ( " 2/8/2008 " , to_string ( shortdate , " 20080208 " ) ) , %% both regged format and parser
? _ assertEqual ( " 2/8/2008 12:00am " , to_string ( longdate , " 2008-02-08 12:00am " ) ) ,
? _ assertEqual ( " 2/8/2008 12:00am " , to_string ( longdate , " 20080208 " ) )
] } .
2014-08-23 00:29:59 -05:00
arith_tests ( _ ) - >
{ inorder , [
? _ assertEqual ( { { 2012 , 2 , 29 } , { 23 , 59 , 59 } } , to_date ( add_seconds ( - 1 , { { 2012 , 3 , 1 } , { 0 , 0 , 0 } } ) ) ) ,
? _ assertEqual ( { { 2013 , 2 , 28 } , { 23 , 59 , 59 } } , to_date ( add_seconds ( - 1 , { { 2013 , 3 , 1 } , { 0 , 0 , 0 } } ) ) ) ,
? _ assertEqual ( { { 2015 , 1 , 1 } , { 0 , 0 , 0 } } , to_date ( add_years ( 1 , { { 2014 , 1 , 1 } , { 0 , 0 , 0 } } ) ) ) ,
? _ assertEqual ( { { 2015 , 1 , 1 } , { 0 , 0 , 0 } } , to_date ( add_seconds ( 1 , { { 2014 , 12 , 31 } , { 23 , 59 , 59 } } ) ) ) ,
? _ assertEqual ( { { 2015 , 1 , 1 } , { 0 , 0 , 59 } } , to_date ( add_minutes ( 1 , { { 2014 , 12 , 31 } , { 23 , 59 , 59 } } ) ) ) ,
? _ assertEqual ( { { 2015 , 1 , 1 } , { 0 , 59 , 59 } } , to_date ( add_hours ( 1 , { { 2014 , 12 , 31 } , { 23 , 59 , 59 } } ) ) ) ,
? _ assertEqual ( { { 2015 , 1 , 1 } , { 23 , 59 , 59 } } , to_date ( add_days ( 1 , { { 2014 , 12 , 31 } , { 23 , 59 , 59 } } ) ) ) ,
? _ assertEqual ( { { 2015 , 1 , 7 } , { 23 , 59 , 59 } } , to_date ( add_weeks ( 1 , { { 2014 , 12 , 31 } , { 23 , 59 , 59 } } ) ) ) ,
? _ assertEqual ( { { 2015 , 1 , 31 } , { 23 , 59 , 59 } } , to_date ( add_months ( 1 , { { 2014 , 12 , 31 } , { 23 , 59 , 59 } } ) ) ) ,
2014-08-23 01:22:15 -05:00
? _ assertEqual ( { { 2015 , 2 , 28 } , { 0 , 0 , 0 } } , to_date ( add_months ( 2 , { { 2014 , 12 , 31 } , { 0 , 0 , 0 } } ) ) ) ,
? _ assertEqual ( { { 2016 , 2 , 28 } , { 0 , 0 , 0 } } , to_date ( add_years ( 1 , { { 2015 , 2 , 28 } , { 0 , 0 , 0 } } ) ) ) ,
? _ assertEqual ( { { 2014 , 2 , 28 } , { 0 , 0 , 0 } } , to_date ( add_months ( - 24 , { { 2016 , 2 , 29 } , { 0 , 0 , 0 } } ) ) ) ,
? _ assertEqual ( { { 2012 , 2 , 29 } , { 0 , 0 , 0 } } , to_date ( add_months ( - 48 , { { 2016 , 2 , 29 } , { 0 , 0 , 0 } } ) ) ) ,
? _ assertEqual ( { { 2016 , 2 , 29 } , { 0 , 0 , 0 } } , to_date ( add_months ( - 1 , { { 2016 , 3 , 31 } , { 0 , 0 , 0 } } ) ) ) ,
? _ assertEqual ( { { 2017 , 2 , 28 } , { 0 , 0 , 0 } } , to_date ( add_years ( 1 , { { 2016 , 2 , 29 } , { 0 , 0 , 0 } } ) ) ) ,
2014-08-23 00:29:59 -05:00
? _ assertEqual ( { { 2015 , 3 , 1 } , { 0 , 0 , 0 } } , to_date ( add_days ( 1 , { { 2015 , 2 , 28 } , { 0 , 0 , 0 } } ) ) ) ,
2014-08-23 01:22:15 -05:00
? _ assertEqual ( { { 2015 , 3 , 3 } , { 0 , 0 , 0 } } , to_date ( add_days ( 3 , { { 2015 , 2 , 28 } , { 0 , 0 , 0 } } ) ) )
2014-08-23 00:29:59 -05:00
] } .
2013-04-24 01:07:16 -05:00
2013-03-25 11:52:14 -05:00
start_test ( ) - >
2013-04-24 01:07:16 -05:00
application : start ( qdate ) ,
set_timezone ( ? SELF_TZ ) ,
set_timezone ( ? SITE_KEY , ? SITE_TZ ) ,
set_timezone ( ? USER_KEY , ? USER_TZ ) ,
register_parser ( compressed , fun compressed_parser / 1 ) ,
register_parser ( microsoft_date , fun microsoft_parser / 1 ) ,
2016-04-13 19:38:04 -05:00
register_parser ( parse_relative , fun parse_relative / 1 ) ,
2013-04-24 01:07:16 -05:00
register_format ( shortdate , " n/j/Y " ) ,
register_format ( longdate , " n/j/Y g:ia " ) .
2013-03-26 01:46:33 -05:00
compressed_parser ( List ) when length ( List ) == 8 - >
2013-04-24 01:07:16 -05:00
try re : run ( List , " ^( \\ d{4})( \\ d{2})( \\ d{2})$ " , [ { capture , all_but_first , list } ] ) of
nomatch - > undefined ;
{ match , [ Y , M , D ] } - >
Date = { list_to_integer ( Y ) , list_to_integer ( M ) , list_to_integer ( D ) } ,
case calendar : valid_date ( Date ) of
true - >
{ Date , { 0 , 0 , 0 } } ;
false - > undefined
end
catch
_ : _ - > undefined
end ;
2013-03-26 01:46:33 -05:00
compressed_parser ( _ ) - >
2013-04-24 01:07:16 -05:00
undefined .
2013-03-26 01:46:33 -05:00
microsoft_parser ( FloatDate ) when is_float ( FloatDate ) - >
2013-04-24 01:07:16 -05:00
try
DaysSince1900 = floor ( FloatDate ) ,
Days0to1900 = calendar : date_to_gregorian_days ( 1900 , 1 , 1 ) ,
GregorianDays = Days0to1900 + DaysSince1900 ,
Date = calendar : gregorian_days_to_date ( GregorianDays ) ,
Seconds = round ( 86400 * ( FloatDate - DaysSince1900 ) ) ,
Time = calendar : seconds_to_time ( Seconds ) ,
{ Date , Time }
catch
_ : _ - > undefined
end ;
2013-03-26 01:46:33 -05:00
microsoft_parser ( _ ) - >
2013-04-24 01:07:16 -05:00
undefined .
2013-03-26 01:46:33 -05:00
2013-04-24 01:07:16 -05:00
2013-03-25 11:52:14 -05:00
stop_test ( _ ) - >
2013-04-24 01:07:16 -05:00
ok .