1: %%
    2: %% %CopyrightBegin%
    3: %%
    4: %% Copyright Ericsson AB 1997-2010. All Rights Reserved.
    5: %%
    6: %% The contents of this file are subject to the Erlang Public License,
    7: %% Version 1.1, (the "License"); you may not use this file except in
    8: %% compliance with the License. You should have received a copy of the
    9: %% Erlang Public License along with this software. If not, it can be
   10: %% retrieved online at http://www.erlang.org/.
   11: %%
   12: %% Software distributed under the License is distributed on an "AS IS"
   13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
   14: %% the License for the specific language governing rights and limitations
   15: %% under the License.
   16: %%
   17: %% %CopyrightEnd%
   18: %%
   19: -module(calendar_SUITE).
   20: 
   21: -include_lib("test_server/include/test_server.hrl").
   22: 
   23: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 
   24: 	 init_per_group/2,end_per_group/2, 
   25: 	 gregorian_days/1,
   26: 	 gregorian_seconds/1,
   27: 	 day_of_the_week/1,
   28: 	 day_of_the_week_calibrate/1,
   29: 	 leap_years/1,
   30: 	 last_day_of_the_month/1,
   31: 	 local_time_to_universal_time_dst/1,
   32: 	 iso_week_number/1]).
   33: 
   34: -define(START_YEAR, 1947).			
   35: -define(END_YEAR, 2012).
   36: 
   37: suite() -> [{ct_hooks,[ts_install_cth]}].
   38: 
   39: all() -> 
   40:     [gregorian_days, gregorian_seconds, day_of_the_week,
   41:      day_of_the_week_calibrate, leap_years,
   42:      last_day_of_the_month, local_time_to_universal_time_dst, iso_week_number].
   43: 
   44: groups() -> 
   45:     [].
   46: 
   47: init_per_suite(Config) ->
   48:     Config.
   49: 
   50: end_per_suite(_Config) ->
   51:     ok.
   52: 
   53: init_per_group(_GroupName, Config) ->
   54:     Config.
   55: 
   56: end_per_group(_GroupName, Config) ->
   57:     Config.
   58: 
   59: gregorian_days(doc) ->
   60:     "Tests that date_to_gregorian_days and gregorian_days_to_date "
   61:     "are each others inverses from ?START_YEAR-01-01 up to ?END_YEAR-01-01. "
   62:     "At the same time valid_date is tested.";
   63: gregorian_days(suite) ->
   64:     [];
   65: gregorian_days(Config) when is_list(Config) ->
   66:     ?line Days = calendar:date_to_gregorian_days({?START_YEAR, 1, 1}),
   67:     ?line MaxDays = calendar:date_to_gregorian_days({?END_YEAR, 1, 1}),
   68:     ?line check_gregorian_days(Days, MaxDays).
   69: 
   70: gregorian_seconds(doc) ->
   71:     "Tests that datetime_to_gregorian_seconds and "
   72:     "gregorian_seconds_to_date are each others inverses for a sampled "
   73:     "number of seconds from ?START_YEAR-01-01 up to ?END_YEAR-01-01: We check "
   74:     "every 2 days + 1 second.";
   75: gregorian_seconds(suite) ->
   76:     [];
   77: gregorian_seconds(Config) when is_list(Config) ->
   78:     ?line Secs = calendar:datetime_to_gregorian_seconds({{?START_YEAR, 1, 1},
   79: 							 {0, 0, 0}}),
   80:     ?line MaxSecs = calendar:datetime_to_gregorian_seconds({{?END_YEAR, 1, 1},
   81: 							    {0, 0, 0}}),
   82:     ?line check_gregorian_seconds(Secs, MaxSecs).
   83: 
   84: day_of_the_week(doc) ->
   85:     "Tests that day_of_the_week reports correctly the day of the week from "
   86:     "year ?START_YEAR up to ?END_YEAR.";
   87: day_of_the_week(suite) ->
   88:     [];
   89: day_of_the_week(Config) when is_list(Config) ->
   90:     ?line Days = calendar:date_to_gregorian_days({?START_YEAR, 1, 1}),
   91:     ?line MaxDays = calendar:date_to_gregorian_days({?END_YEAR, 1, 1}),
   92:     ?line DayNumber = calendar:day_of_the_week({?START_YEAR, 1, 1}),
   93:     ?line check_day_of_the_week(Days, MaxDays, DayNumber).
   94: 
   95: day_of_the_week_calibrate(doc) ->
   96:     "Tests that day_of_the_week for 1997-11-11 is Tuesday (2)";
   97: day_of_the_week_calibrate(suite) ->
   98:     [];
   99: day_of_the_week_calibrate(Config) when is_list(Config) ->
  100:     ?line 2 = calendar:day_of_the_week({1997, 11, 11}).
  101: 
  102: leap_years(doc) ->
  103:     "Tests that is_leap_year reports correctly the leap years from "
  104:     "year ?START_YEAR up to ?END_YEAR.";
  105: leap_years(suite) ->
  106:     [];
  107: leap_years(Config) when is_list(Config) ->
  108:     ?line check_leap_years(?START_YEAR, ?END_YEAR).
  109: 
  110: last_day_of_the_month(doc) ->
  111:     "Tests that last_day_of_the_month reports correctly from "
  112:     "year ?START_YEAR up to ?END_YEAR.";
  113: last_day_of_the_month(suite) ->
  114:     [];
  115: last_day_of_the_month(Config) when is_list(Config) ->
  116:     ?line check_last_day_of_the_month({?START_YEAR, 1}, {?END_YEAR, 1}).
  117: 
  118: local_time_to_universal_time_dst(doc) ->
  119:     "Tests local_time_to_universal_time_dst for MET";
  120: local_time_to_universal_time_dst(suite) ->
  121:     [];
  122: local_time_to_universal_time_dst(Config) when is_list(Config) ->
  123:     case os:type() of
  124: 	{unix,_} ->
  125: 	    case os:cmd("date '+%Z'") of
  126: 		"SAST"++_ ->
  127: 		    {comment, "Spoky time zone with zero-set DST, skipped"};
  128: 		_ ->
  129: 		    local_time_to_universal_time_dst_x(Config)
  130: 	    end;
  131: 	_ ->
  132: 	    local_time_to_universal_time_dst_x(Config)
  133:     end.
  134: local_time_to_universal_time_dst_x(Config) when is_list(Config) ->
  135:     %% Assumes MET (UTC+1 / UTC+2(dst)
  136:     ?line LtW   = {{2003,01,15},{14,00,00}}, % Winter
  137:     ?line UtW   = {{2003,01,15},{13,00,00}}, % 
  138:     ?line UtWd  = {{2003,01,15},{12,00,00}}, % dst
  139:     ?line LtS   = {{2003,07,15},{14,00,00}}, % Summer
  140:     ?line UtS   = {{2003,07,15},{13,00,00}}, % 
  141:     ?line UtSd  = {{2003,07,15},{12,00,00}}, % dst
  142:     ?line LtWS  = {{2003,03,30},{02,30,00}}, % Winter->Summer
  143:     ?line UtWS  = {{2003,03,30},{01,30,00}}, % 
  144:     ?line UtWSd = {{2003,03,30},{00,30,00}}, % dst
  145:     ?line LtSW  = {{2003,10,26},{02,30,00}}, % Summer->Winter
  146:     ?line UtSW  = {{2003,10,26},{01,30,00}}, % 
  147:     ?line UtSWd = {{2003,10,26},{00,30,00}}, % dst
  148:     %%
  149:     ?line UtW   = calendar:local_time_to_universal_time(LtW, false),
  150:     ?line UtWd  = calendar:local_time_to_universal_time(LtW, true),
  151:     ?line UtW   = calendar:local_time_to_universal_time(LtW, undefined),
  152:     %%
  153:     ?line UtS   = calendar:local_time_to_universal_time(LtS, false),
  154:     ?line UtSd  = calendar:local_time_to_universal_time(LtS, true),
  155:     ?line UtSd  = calendar:local_time_to_universal_time(LtS, undefined),
  156:     %%
  157:     case calendar:local_time_to_universal_time(LtWS, false) of
  158: 	UtWS ->
  159: 	    ?line UtWSd = calendar:local_time_to_universal_time(LtWS, true),
  160: 	    ?line []    = calendar:local_time_to_universal_time_dst(LtWS),
  161: 	    %%
  162: 	    ?line UtSW  = calendar:local_time_to_universal_time(LtSW, false),
  163: 	    ?line UtSWd = calendar:local_time_to_universal_time(LtSW, true),
  164: 	    ?line [UtSWd, UtSW] = calendar:local_time_to_universal_time_dst(LtSW),
  165: 	    ok;
  166: 	{{1969,12,31},{23,59,59}} ->
  167: 	    %% It seems that Apple has no intention of fixing this bug in
  168: 	    %% Mac OS 10.3.9, and we have no intention of implementing a
  169: 	    %% workaround. 
  170: 	    {comment,"Bug in mktime() in this OS"}
  171:     end.
  172: 
  173: iso_week_number(doc) ->
  174: 	"Test the iso week number calculation for all three possibilities."
  175: 	" When the date falls on the last week of the previous year,"
  176: 	" when the date falls on a week within the given year and finally,"
  177: 	" when the date falls on the first week of the next year.";
  178: iso_week_number(suite) ->
  179: 	[];
  180: iso_week_number(Config) when is_list(Config) ->
  181: 	?line check_iso_week_number().
  182: 
  183: %%
  184: %% LOCAL FUNCTIONS
  185: %%
  186: 
  187: %% check_gregorian_days
  188: %% 
  189: check_gregorian_days(Days, MaxDays) when Days < MaxDays ->
  190:     ?line Date = calendar:gregorian_days_to_date(Days), 
  191:     ?line true = calendar:valid_date(Date),
  192:     ?line Days = calendar:date_to_gregorian_days(Date),
  193:     ?line check_gregorian_days(Days + 1, MaxDays);
  194: check_gregorian_days(_Days, _MaxDays) ->
  195:     ok.
  196: 
  197: %% check_gregorian_seconds
  198: %% 
  199: %% We increment with something prime (172801 = 2 days + 1 second).
  200: %%
  201: check_gregorian_seconds(Secs, MaxSecs) when Secs < MaxSecs ->
  202:     ?line DateTime = calendar:gregorian_seconds_to_datetime(Secs), 
  203:     ?line Secs = calendar:datetime_to_gregorian_seconds(DateTime),
  204:     ?line check_gregorian_seconds(Secs + 172801, MaxSecs);
  205: check_gregorian_seconds(_Secs, _MaxSecs) ->
  206:     ok.
  207: 
  208: 
  209: %% check_day_of_the_week
  210: %%
  211: check_day_of_the_week(Days, MaxDays, DayNumber) when Days < MaxDays ->
  212:     ?line Date = calendar:gregorian_days_to_date(Days),
  213:     ?line DayNumber = calendar:day_of_the_week(Date),
  214:     ?line check_day_of_the_week(Days + 1, MaxDays, 
  215: 				((DayNumber rem 7) + 1));
  216: check_day_of_the_week(_Days, _MaxDays, _DayNumber) ->
  217:     ok.
  218: 
  219: %% check_leap_years
  220: %%
  221: %% SYr must be larger than 1800, and EYr must be less than ?END_YEAR.
  222: %%
  223: check_leap_years(SYr, EYr) when SYr < EYr ->
  224:     ?line Rem = SYr rem 4,
  225:     case Rem of
  226: 	0 ->
  227: 	    case SYr of
  228: 		1900 ->
  229: 		    ?line false = calendar:is_leap_year(SYr);
  230: 		2000 ->
  231: 		    ?line true = calendar:is_leap_year(SYr);
  232: 		_  ->
  233: 		    ?line true = calendar:is_leap_year(SYr)
  234: 	    end;
  235: 	_ ->
  236: 	    ?line false = calendar:is_leap_year(SYr)
  237:     end,
  238:     check_leap_years(SYr + 1, EYr);
  239: check_leap_years(_SYr, _EYr) ->
  240:     ok.
  241: 
  242: check_last_day_of_the_month({SYr, SMon}, {EYr, EMon}) when SYr < EYr ->
  243:     ?line LastDay = calendar:last_day_of_the_month(SYr, SMon),
  244:     ?line LastDay = case SMon of
  245: 			 1 -> 31;
  246: 			 2 ->
  247: 			     case calendar:is_leap_year(SYr) of
  248: 				 true -> 29;
  249: 				 false  -> 28
  250: 			     end;
  251: 			 3 -> 31;
  252: 			 4 -> 30;
  253: 			 5 -> 31;
  254: 			 6 -> 30;
  255: 			 7 -> 31;
  256: 			 8 -> 31;
  257: 			 9 -> 30;
  258: 			 10 -> 31;
  259: 			 11 -> 30;
  260: 			 12 -> 31
  261: 		     end,
  262:     ?line NYr = case SMon of
  263: 		    12 -> SYr + 1;
  264: 		    _ -> SYr
  265: 		end,
  266:     ?line check_last_day_of_the_month({NYr, (SMon rem 12) + 1}, 
  267: 				      {EYr, EMon});
  268: check_last_day_of_the_month(_, _) ->
  269:     ok.
  270: 
  271: %% check_iso_week_number
  272: %%
  273: check_iso_week_number() ->
  274:     ?line {2004, 53} = calendar:iso_week_number({2005, 1, 1}),
  275:     ?line {2007, 1} = calendar:iso_week_number({2007, 1, 1}),
  276:     ?line {2009, 1} = calendar:iso_week_number({2008, 12, 29}).
  277:     
  278: 
  279: