Broad definition of dates - working on an example and a bug (?)


(Bruno Moreira) #1

Dear all,
following something I’ve posted in the old forum, I’m working on something to handle the collection of documents which can have partial dates:

  1. I’m collecting PLANS (prototype plano_p in attached file);
  2. Each PLAN can have multiple DOCUMENTS (prototype documento_p in attached file);;
  3. Each DOCUMENT can have multiple DATES (prototype data_doc_p in attached file);
  4. Each DATE can be defined in one of three ways:
    a- year (eg. 1980);
    b- year and month (eg. 1980-02);
    c- year, month and day (eg. 1980-02-10).

Meaning, inside a PLAN I have multiple DOCS, each with multiple DATES (as children notes: their $Text is passed onto a $KeyAttribute, which is then queried for the number of values to determine the INITIAL DATE and FINAL DATE based on the original DATE).

This means:

  • if the DATE is defined as 1980,
    INITIAL DATE will become 01/01/1980 00:00 and
    FINAL DATE will become 31/12/1980 23:59
    (i.e. whole year);

  • if the DATE is defined as 1980-03,
    INITIAL DATE will become 01/03/1980 00:00 and
    FINAL DATE will become 31/03/1980 23:59
    (i.e whole month);

  • if the DATE is defined as 1980-03-20,
    INITIAL DATE will become 20/03/1980 00:00 and
    FINAL DATE will become 20/03/1980 23:59
    (i.e whole day);

These calculations are made on the notes with the DATE prototype; then the DOC will collect all the initial and final dates and assign the minimum initial date and maximum final date to itself; and then the PLAN will do the same for all DOCS, meaning:

  • the initial date of the PLAN is the newest initial date of all DOCS that make part of it;

  • the final date of the PLAN is the oldest final date of all DOCS that make part of it;

  • the initial date of the DOC is the newest initial date of all DATES that make part of it;

  • the final date of the DOC is the oldest final date of all DATES that make part of it;

It seems to be working quite ok, except when defining older dates with YYYY-MM only. In the TBX attached to this post you will find a note, highlighted in red, where the problem occurs:

The note “1920-03” gets correctly assigned the INITIAL DATE of 01/03/1920 00:00, but the wrong FINAL DATE of 07/05/2056, 23:59;

However, the note “1970-03” gets correctly assigned both INITIAL and FINAL DATES, i.e. 01/03/1970, 00:00 and 31/03/1970, 23:59.

“1920” and “1920-03-20” also get evaluated ok. The problem is only when the date is defined only by year and month, and I suspect it must have something to do with what I’ve setup to calculate the last day of the month:

if ($data_doc_p_parcial.count == 2) {
$data_doc_p_final_norm = date("01/" + $data_doc_p_parcial.at(1) + "/" +      $data_doc_p_parcial.at(0));
$data_doc_p_final_norm = date((($data_doc_p_final_norm +1month)-1day));
};

(when encountering a date defined by 2 parameters (i.e. YYYY and MM) it makes the FINAL DATE first become the first day of that month, then adds 1 month and subtracts 1 day).

PHEW. Hope it made sense and you can help me find the bug or the problem on my code or a cleaner way to do all this.

Here is the TBX file:
broadDefinitionOfDates.tbx (86.8 KB)

PS: I’m loading edicts into the prototypes through their rules which fetch a specific note’s $Text (feels more comfortable to edit the code in this way…)

Thanks! I’d like to post this in the examples when ready. May be of some use :wink:


(Mark Anderson) #2

I don’t think this can be fixed at present as there appears to be a data arithmetic glitch when manipulating dates before 1970. I’ve reported the issue to tech support.

Although the following factors don’t seem to break anything, i’d recommend them as best practice:

  • Add the “Code” prototype and use that for your notes used to hold code (i.e. your edict code). This avoids things like straight quotes being ‘corrected’ to curly quotes, etc.
  • Use a List type attribute for your $data_doc_p_parcial attribute.
  • Avoid comments in your code. There is no specified form of commenting for action code. Your method could easily be mistaken by the parser for a literal path ($Path) in the document.

As said above, until there is some feedback on the date arithmetic issue, i’m not sure how to fix this.


(Mark Anderson) #4

$data_doc_p_parcial = $Name.replace("-",";");

I read it as parsing a string ($Name) to replace hyphens with semi-colons. I grant you a list (List or Set types) is ‘just’ a string containing semi-colon value delimiter. String does have a String.countOccurrencesOf("string") but not a String.count. So, in line:

if ($data_doc_p_parcial.count == 1)

The String-type $data_doc_p_parcial is being coerce to a list to parse it and then use list.at(N) calls on it.

Thus my suggestion to use a List type to hold what is going to be treated as if a list.

For comparatively complex code like this I’d avoid implicit data type coercions, especially given the otherwise precise use of user attribute names. If it comes across as simply pedantic, I apologise. :slight_smile:


(Bruno Moreira) #5

Thanks for the replies and suggestions. I think I’ll resort doing it the “hard way” for now, i.e. determining the last day of a month as 28,30 or 31 depending on the month, using if clauses (and considering that 29th February is irrelevant) :slight_smile:

EDIT: thought of a quick and ugly workaround which seems to work:

  • save the YYYY to a temporary key attribute of type number;

  • perform the calculation (+1month, -1day) with a year that works (eg. 2000);

  • after the calculation is done, replace the year with the saved one via

    year($data_doc_p_final_norm,$data_doc_p_anoTemp);

It works!
:smiley:

EDIT 2: It seems to work except when the month is February (eg. 1970-02) which will make the end date be the 1st of March instead of 28th February. But with another ugly fix it works (I can check if the starting month is 2 and the ending month is 3 – if so, force the month to be 2 and the day to be 28). Ok, once again I’ll lose the 29th February cases … but they are negligible!


(Mark Anderson) #6

Another approach is to use a look-up table. Here I use English short months but you can substitute those if your system is set for another language - use whatever date format “M” generated on you Mac.:

$LastDayList = "Feb:28;Apr|Jun|Sep|Nov:30;Jan|Mar|May|Jul|Aug|Oct|Dec:31;default:0";

$MyString = $SomeDate.format(“M”);
$MyValue = $LastDayList.at($MyString);

So if Date-type attribute $SomeDate was 5 April 2016, $MyValue would be set to 30. I’d note this method doesn’t allow for leap years.

Why not just use numbers as the key values? It turns out (I need to update my article on look-up tables) that keys must be strings that aren’t numbers. “A2B” is fine but “2” is not.

HTH.


(Bruno Moreira) #7

Thanks for the suggestion Mark. I’ve been neglecting lookup tables, but will pay more attention to them now!


(Mark Anderson) #8

Another suggestion (as provided elsewhere by @eastgate), but again which doesn’t deal with leap-years:

You could also use a list and just use the month number as an index:

$MyList: "31;28;31;30;31;30....
$MyList.at(2) is the number of days in February

(eastgate) #9

The problem with date arithmetic in older dates has been resolved; the fix will be in the next backstage release.


(Bruno Moreira) #10

@mwra good idea as well!
@eastgate guess I’ll need to start saving to renew the license :sweat: