# Suppressing DateString default behavior when parts of date are missing

By subsampling data from a Excel spreadsheet I have created a Mathematica dataset that I then seek to modify by applying various functions to the fields to convert these data into a different flat file format in a sorted order for eventual output.

One field of the dataset that I wish to format involves the date at which a particular collection was made. In particular, one key value pair(column name & value) contains dates typically in the format "1950/2/20" that I wish to convert to "20 Feb 1950". Consequently, I am trying to make the conversion in a statement:

 bskudatasorted2 =  bskudatasorted[All, {"BSKUno" -> bskunoconvert,  "LocalityEn" -> bskulocalityconvert, "CollDateFrom" -> bskucolldatefromconvert}]


where bskudatasorted is the dataset in sorted order and where bskucolldateformatconvert is a overloaded function designed to deal with specific entries that do not quite conform to the expected pattern given above (ie such as "","Null", 1952/**/**, "1952/02/**"etc.). Taking one signature of this overloaded function, namely,

bskucolldatefromconvert[x_ /; StringMatchQ[x, __ ~~ "/" ~~ "**" ~~ "/" ~~"**"]] :=  Module[{y1}, y1 = DateString[DateObject[x ], {"Year"}];Return[y1]];


However, this function fails to provide the correct date conversion (the functions bskunoconvert and bskulocalityconvert work fine but there is an error in my function bskucolldatefromconvert) and the overloaded function returns a rather cryptic error: Failure. Message Template: Message:ssgl; MessageParameters{\$MessageList} Tag: Message.

To debug this I have simply imported one test entry (ie skudatasorted[[211,36]]) with the day and month missing to understand why it is not working as expected. I do this as follows:

bskudatasorted[[211, 36]]


and get out the String "1952/**/**" as expected

If I execute

DateObject[bskudatasorted[[211,36]]


I then get out a DateObject with the correct date (ie. "Year: 1952")

If I then execute the following:

DateString[DateObject[bskudatasorted[[211, 36]]], "Year"]


I also get out the correct year

Out[109]="1952"

If further executing

StringMatchQ[bskudatasorted[[211, 36]], __ ~~ "/" ~~ "**" ~~ "/" ~~ "**"]


I get Out[113]= True

Again, indicating that this entry is being corrected identified as having the appropriate pattern for conditional execution.

And again, at this point:

In[104]:= Head[%] gives me, as expected,

Out[104]= String

that indicates that the entry reported is in fact a String.

However, if I attempt to call the function as:

bskucolldatefromconvert[bskudatasorted[[211, 36]]]


I do not get the correct/expected date but rather:

Out[116]= "Tue Jan 1952"

. It would seem that the default behavior of DateString somehow needs to be overridden when part of the date string is missing.

How do I suppress the default behavior when some elements of the date are missing or otherwise alter my function and those in other signatures (e.g. when only Month and Year are present) so that the correct date (ie only "1952" in this case) is returned when parts of the date are missing?

• From the docs for DateString; "Those not filled in are taken to have default values {Subscript[y, c],1,1,0,0,0}, where Subscript[y, c] is the current year." That is you have only specified "Year" and so date string is filling in the rest as per the documentation. See DateValue for year only dates. Feb 15, 2019 at 0:01
• Exactly, that is why I am looking to understand how to either to suppress this default behavior or to find an alternative solution. Some data elements have no day or month, so I need for my conversion function to reflect this unavoidable fact. Feb 15, 2019 at 1:36
• Which version are you using? In 11.3 DateString[DateObject@"1952/**/**", {"Year"}] returns "1952". Feb 15, 2019 at 2:07
• I'm using version 11.3. Feb 15, 2019 at 5:21

As Edmund noted I find that the following modules work:

bskucolldatefromconvert[x_] := Module[{y1}, y1 = DateString[DateObject[x, "Year"]]; Return[y1]];


does indeed work when given "1952/**/**"

Likewise,

bskucolldatefromconvert[x_] := Module[{y1}, y1= DateString[DateObject[x ], {"MonthNameShort", " ", "Year"}]; Return[y1]];


works, when given "1952/05/**

So this question is answered, but uncovers another problem with attempting to distinguish the first pattern from the second, since it seems that the "*" is treated as a wildcard specifier in the conditional statements rather than simply a character (neither NumberDigit or LetterCharacter):

 bskucolldatefromconvert[x_ /; StringMatchQ[x, Repeated[DigitCharacter] ~~ /" ~~ Repeated[DigitCharacter] ~~ "/" ~~ Repeated[DigitCharacter]]] := Module[{y1}, y1 = DateString[DateObject[ToString[x ], {"DayShort", " ", "MonthNameShort", " ", "Year"}]]; Return[y1]];

bskucolldatefromconvert[x_ /; StringMatchQ[x, Repeated[DigitCharacter] ~~ "/" ~~ Repeated["*"] ~~ "/" ~~ Repeated["*"]]] :=   Module[{y1}, y1 = DateString[DateObject[x, "Year"]]; Return[y1]];

bskucolldatefromconvert[x_ /; StringMatchQ[x, DigitCharacter .. "/" ~~ DigitCharacter ~~ "/" ~~ Repeated["*"]]] := Module[{y1}, y1 = DateString[DateObject[x ], {"MonthNameShort", " ", "Year"}]; Return[y1]];


which, though overloaded always seem to execute only that signature that gives the year only, even when year/mon/day are all present.

Perhaps, after a bit more fiddling I'll figure out how to specify the conditional statements to correctly distinguish among the possibilities (ie. "1957/07/02","1952/07/**", and "1952/**/**}

• You can use regexes instead of string expressions: RegularExpression["\\d{4}/\\d{2}/\\d{2}"] for "1957/07/02", RegularExpression["\\d{4}/\\d{2}/\\*{2}"] for "1957/07/**", RegularExpression["\\d{4}/\\*{2}/\\*{2}"] for "1957/**/**". Feb 15, 2019 at 7:38
• Thanks Alexey, I was struggling with the corresponding string expression of "1957/07/**", having obtained the other two patterns with string expressions. Clearly, more familiarity with regular expressions would pay off handsomely. You make it look easy. My thanks to you and Edmund. Feb 15, 2019 at 14:01