(* :Title: DateFunctions *) (* :Author: Mark Fisher *) (* :Date: July 2005 *) (* :Package Version: 0.1 *) (* :Summary: A number of functions to convert dates between list, string, and integer representations. The options have the same form as ConversionOptions for Import for "CSV" files. *) BeginPackage["DateFunctions`", {"Miscellaneous`Calendar`"}] DateToIndex::usage = "DateToIndex[{year, month, day}] converts the date to an integer using {1900, 1, 1} as the base day. DateToIndex[{year, month}] converts the date to an integer using {1900, 1} as the base month. In either case, a different base can be specified as a second argument." DayIndexToDate::usage = "DayIndexToDate[index] converts the integer index to {year, month, day} using {1900, 1, 1} as the base day. A different base can be specified as a second argument." MonthIndexToDate::usage = "MonthIndexToDate[index] converts the integer index to {year, month} using {1900, 1} as the base month. A different base can be specified as a second argument." StringDateToListDate::usage = "StringDateToListDate[date, opts] returns a date of the form {y, m, d} given the string of the form \"yyyy/mm/dd\". StringDateToListDate takes three options. \"DateStyle\" has settings \"Scientific\" (the default), \"American\" (\"mm/dd/yyyy\"), or \"European\" (\"dd/mm/yyyy\"). \"DateSeparator\" has default setting \"/\". \"TwoDigitYearFunction\" has default None (and has not yet been implemented). StringDateToListDate also works with dates of the form \"yyyy/mm\" and \"mm/yyyy\", etc." StringDateToIntegerDate::usage = "StringDateToIntegerDate[date, opts] returns an integer of the form yyyymmdd given the string of the form \"yyyy/mm/dd\". StringDateToListDate takes three options. \"DateStyle\" has settings \"Scientific\" (the default), \"American\" (\"mm/dd/yyyy\"), or \"European\" (\"dd/mm/yyyy\"). \"DateSeparator\" has default setting \"/\". \"TwoDigitYearFunction\" has default None (and has not yet been implemented)." ListDateToStringDate::usage = "ListDateToStringDate[{y, m, d}, opts] returns a date of the form \"yyyy/mm/dd\". StringDateToListDate takes three options. \"DateStyle\" has settings \"Scientific\" (the default), \"American\" (\"mm/dd/yyyy\"), or \"European\" (\"dd/mm/yyyy\"). \"DateSeparator\" has default setting \"/\". \"TwoDigitYear\" has default False." IntegerDateToStringDate::usage = "IntegerDateToStringDate[int] take an integer of the form yyyymmdd and returns a string date of the \"Scientific\" form \"yyyy/mm/dd\". IntegerDateToStringDate takes three options. \"DateStyle\" has settings \"Scientific\" (the default), \"American\" (\"mm/dd/yyyy\"), or \"European\" (\"dd/mm/yyyy\"). \"DateSeparator\" has default setting \"/\". \"TwoDigitYear\" has default False (and has not yet been implemented)." ListDateToIntegerDate::usage = "ListDateToIntegerDate[{year, month, day}] returns an integer of the form yyyymmdd. ListDateToIntegerDate[{year, month}] returns an integer of the form yyyymm." IntegerDateToListDate::usage "IntegerDateToListDate[int] returns a list of the form {yyyy, mm, dd} or {yyyy, mm} depending on the magnitude of the integer." Begin["Private`"] (***** code starts here *****) DateToIndex[date : {y_, m_}, base_:{1900, 1}] := {12, 1}.(date - base) DateToIndex[date : {y_, m_, d_}, base_:{1900, 1, 1}] := DaysBetween[base, date] DayIndexToDate[i_Integer, base_:{1900, 1, 1}] := DaysPlus[base, i] MonthIndexToDate[i_Integer, base_:{1900, 1}] := monthindextodate[i, base] monthindextodate = Compile[{{i, _Integer}, {base, _Integer, 1}}, With[{q = base[[1]] + Quotient[i, 12], m = base[[2]] + Mod[i, 12]}, {q + Quotient[m, 12, 1], Mod[m, 12, 1]} ]] Options[StringDateToListDate] = {"DateStyle" -> "Scientific", "DateSeparator" -> "/", "TwoDigitYearFunction" -> None} StringDateToListDate[date_String, opts___?OptionQ] := Module[{separator, style, fun, split, order}, {separator, style, fun} = {"DateSeparator", "DateStyle", "TwoDigitYearFunction"} /. {opts} /. Options[StringDateToListDate]; split = StringSplit[date, separator]; order = If[Length[split] == 3, (* then *) Switch[style, "Scientific", {1, 2, 3}, "American", {3, 1, 2}, "European", {3, 2, 1}, _, {1, 2, 3}], (* else *) Switch[style, "Scientific", {1, 2}, "American" | "European", {2, 1}, _, {1, 2}] ]; ToExpression[split][[ order ]] ] StringDateToIntegerDate[date_String, opts___?OptionQ] := ListDateToIntegerDate[StringDateToListDate[date, opts]] Options[ListDateToStringDate] = {"DateStyle" -> "Scientific", "DateSeparator" -> "/", "TwoDigitYear" -> False} ListDateToStringDate[{y_Integer, m_Integer, d_Integer}, opts___?OptionQ] := Module[{separator, style, y2, order}, {separator, style, y2} = {"DateSeparator", "DateStyle", "TwoDigitYear"} /. {opts} /. Options[ListDateToStringDate]; order = Switch[style, "Scientific", {1, 2, 3}, "American", {2, 3, 1}, "European", {3, 2, 1}, _, {1, 2, 3}]; StringJoin[ Insert[ {If[TrueQ[y2], StringDrop[#, 2], #]& @ ToString[y], StringJoin @@ (ToString /@ IntegerDigits[m, 10, 2]), StringJoin @@ (ToString /@ IntegerDigits[d, 10, 2])}[[order]], separator, {{2}, {3}} ] ] ] ListDateToStringDate[{y_Integer, m_Integer}, opts___?OptionQ] := Module[{separator, style, fun, order}, {separator, style, y2} = {"DateSeparator", "DateStyle", "TwoDigitYear"} /. {opts} /. Options[ListDateToStringDate]; order = Switch[style, "Scientific", {1, 2}, "American" | "European", {2, 1}, _, {1, 2}]; StringJoin[ Insert[ {If[TrueQ[y2], StringDrop[#, 2], #]& @ ToString[y], StringJoin @@ (ToString /@ IntegerDigits[m, 10, 2])}[[order]], separator, {{2}} ] ] ] Options[IntegerDateToStringDate] = {"DateStyle" -> "Scientific", "DateSeparator" -> "/", "TwoDigitYear" -> False} IntegerDateToStringDate[i_Integer /; i >= 10^6, opts___?OptionQ] := Module[{separator, style, y2, order, list}, {separator, style, y2} = {"DateSeparator", "DateStyle", "TwoDigitYear"} /. {opts} /. Options[ListDateToStringDate]; order = Switch[style, "Scientific", {1, 2, 3}, "American", {3, 1, 2}, "European", {3, 2, 1}, _, {1, 2, 3}]; list = StringSplit[StringInsert[ToString[i], " ", {5, 7}]][[ order ]]; StringJoin @@ Most[Flatten[Transpose[{list, {separator, separator, ""}}]]] ] IntegerDateToStringDate[i_Integer /; i < 10^6, opts___?OptionQ] := Module[{separator, style, y2, order, list}, {separator, style, y2} = {"DateSeparator", "DateStyle", "TwoDigitYear"} /. {opts} /. Options[ListDateToStringDate]; order = Switch[style, "Scientific", {1, 2}, "American" | "European", {2, 1}, _, {1, 2}]; list = StringSplit[StringInsert[ToString[i], " ", {5}]][[ order ]]; StringJoin @@ Most[Flatten[Transpose[{list, {separator, ""}}]]] ] ListDateToIntegerDate[date : {y_Integer, m_Integer, d_Integer}] := date.{10000, 100, 1} ListDateToIntegerDate[date : {y_Integer, m_Integer}] := date.{100, 1} IntegerDateToListDate[i_Integer] := ToExpression @ StringSplit[ StringInsert[ToString[i], " ", If[i < 10^6, {5}, {5, 7}]] ] End[] EndPackage[]