Territory_ConvertTimeFormats
Rick Murray (539) 13806 posts |
Probably immaterial really. You’d only need to set up the field once, not a million times… Don’t forget, BASIC also supports this notation: |
John WILLIAMS (8368) 493 posts |
I’ve been mulling it over whilst making a paella for lunch and concluded that both would be needed. You have to do a conversion to make the subtraction or addition part work, so, to make the calculation sensible, you have to convert back to how you started to get the time right. This you’d do with or without bit 19 0f R3 set, but with zero in R4 or timezone within territory. As I’m not sure what value to put in that last if I wanted to, I’d be tempted to use it with bit 19 still set and zero in R4. Does that make sense? |
Stuart Swales (8827) 1349 posts |
But you’re wanting the ordinals to compose a yyyymmdd filename? So just convert from 5-byte to that, with appropriate offset in R4. |
Rick Murray (539) 13806 posts |
I don’t think it converts to string…? You’d really need to do it in three steps:
Note: the documentation says OS_Word returns a five byte UTC value, not local time, however throwing the five byte read directly at OS_ConvertStandardDateAndTime gave the correct time. Does that SWI automatically translate, or was OS_Word returning local or something? |
Rick Murray (539) 13806 posts |
It seems that this call might be missing something. You can let it work out whether or not to adjust for DST, but it seems that one must supply the appropriate timezone in R4. This is a bit nonsense if you’re not using the default timezone. Might be less trouble to get the current offset using ReadCurrentTimeZone and bung it in manually? One could bump the value by any other desired offset at the same time and thus extinctify two avians with one haematite. |
Alan Adams (2486) 1147 posts |
So did someone actually report that you had to change timezone in order for the code to do the additional offset arithmetic? Brain-dead if true, and needs a BIG note in the documentation. The following, according to the posts made this afternoon, should work. It doesn’t
The reportdumps show that the two 5-byte buffers contain identical values, even though it was told to converty from GMT to UTC. It fails if asked to convert the other way too. Does it need R0 to be something other than -1 for anything to happen? [Edit] The above works if I set bit 18 instead of bit 16. The documentation for bit 18 says "Bit 18: Calculate bit 16 automatically ". |
Alan Adams (2486) 1147 posts |
And this fails with “unsupported subreason”. ???
Without the (1<<19) and the offset it correctly adds 1 hour to the current time. And with the <1<<19) but without ther (1<<18) it correctly adds 3 days and 1 hour. So bits 18 and 19 seem to be mutually exclusive. |
Alan Adams (2486) 1147 posts |
and I can now confirm that if the two timezones are the same, it doesn’t do any arithmetic, merely copies the buffer from input to output unchanged. |
Stuart Swales (8827) 1349 posts |
Cmon it’s not that hard to subtract two 5 byte time values! Especially when the subtrahend is a small positive value ;-) |
John WILLIAMS (8368) 493 posts |
For one who was initially sceptical about the whole idea, or even its possibility, you seem to have developed rather an interest – to the extent that it may be you who is further usefully adding to the Wiki page that Rick initially updated. I look forward to reading about your further discoveries as I take my RISC OS machine off-line for the great ceiling reskim and just follow proceedings for a day or two. An exciting voyage of discovery, whereas my original problem could easily be solved by temporarily using a US time zone where it isn’t even teatime yet whilst creating my date-based filename on turning-in. But that would be cheating. All rather more fun than I imagined! |
Rick Murray (539) 13806 posts |
If by “timezone” you mean local or UTC for both input and output, that’s entirely as expected, the wiki documentation says as much.
Makes sense. On one hand you’re saying “work out if there’s a DST offset and apply it” and on the other you’re saying “apply this offset”.
Exactly what it says. Bit 16 means to convert as if daylight savings was in use. Always.
I think you’re maybe getting a little mixed up here. This wouldn’t ordinarily affect people with simple territories (UK, France, Germany…) as they’ll all only have the one timezone. |
Alan Adams (2486) 1147 posts |
So going back to the OP, the requirement was to take the local time, subtract a few hours and convert it into a formatted date/time string. The reason for trying to use the Territory_ConvertTimeFormats function is that it seems to be the only system-supplied function capable of doing the subtraction. It becomes apparent from the experiments, if not from the rather limited documentation, that the subtraction only occurs as a side effect of a conversion between different timezones, which introduces an additional unwanted offset. So we’re left with the need to do an unsigned 5-byte subtraction in BASIC, which is possible, but not exactly straightforward. After the subtraction there’s a simple Territory function to do the formatting. There are a number of ways to address the subtraction in BASIC, all a little clumsy. The one I prefer is to work byte by byte from LSB to LSB+3, using integers subtraction, and checking for a borrow (bit 8 non-zero). The borrow is then included in the next byte up. Finally subtract the borrow from the LSB. This for subtracting an integer (4-byte) value from the buffer holding a 5-byte value. A similar approach works for 5-byte – 5-byte.
|
Rick Murray (539) 13806 posts |
Who’da thought something so simple would be so complicated? ;) |
nemo (145) 2529 posts |
The method I posted earlier using Ordinals works for adjusting centiseconds, seconds, minutes, hours and (a small number of) days. It does not work for months or greater. But as Stuart has pointed out, adding or subtracting a time offset is simple:
RISC OS is in dire need of a Calendar manipulation API. There was the DateUtils module that used to be distributed with !Allocate, but that was rubbish – even so, I have made a new 32b version of it. But it’s poo as is. There’s an opportunity to add some useful functionality though. |
Alan Adams (2486) 1147 posts |
But does even hours work in the case where subtracting a number of hours also changes the day, and potentially month and year as well. e.g. 1-Jan-2000:01:00:00 – 3 hours, which SHOULD result in 31-Dec-1999:22:00:00. Which is exactly the case the OP was wanting to use it for.
That works in this case because the offset is small enough that the top byte of the integer is zero, so there’s no possibility of a carry into the 5th byte of the time.
Agreed. This discussion has shown up a number of deficiencies in the Territory module for doing this. e.g. The maximum year for ordinals conversion is very different (by 200 years) from the maximum year for dateandtime conversions. The documentation of the format function is minimal, confusing, and in some aspects incomplete/wrong. DateAndTime produces a year in the 1900’s if the top two bytes of the 5-byte time are ffff, It works for ffef, feff and efff. |
nemo (145) 2529 posts |
Yes, it does. But big proviso this is observed behaviour not defined functionality, so I thought I’d do it manually in centiseconds.
Which is the case I was trying to help with. Those few instructions work for offsets of ±248 days, which seems appropriate for an attempt to change a few hours.
This is true of all the documentation, sadly.
The maximum is &FFFFA81BF which is 06:57:57.75 03-Jun-2248. So what API would we like to see? I’d like to resurrect DateUtils, which already has _WeekNo, _AddToDate, _TodaysDate and _CurrentTime SWIs though not because they’re terribly useful. Add/subtract ordinals? “DateUtils_Add”,timeptr,cs,se,mi,hr,dy,mo,yr? A Convert- style adder whose inputs and output can all be different formats (eg this TimeDate plus these Ordinals output as a DateString)? Distressingly, I have written a module that does various timedate manipulations, but I can’t find it right now. |
Jeff Doggett (257) 234 posts |
You’ve misread the code, and misquoted it. |
David J. Ruck (33) 1629 posts |
Rick wrote:
Times and dates are an absolute nightmare, it’s only with Python and its libraries I’ve had confidence to go anywhere near this sort of thing. With the RISC OS APIs, it’s a non starter. |
nemo (145) 2529 posts |
D’oh. It’s my own version of DateUtils, which I’d misplaced: The last version of DateUtils I’m aware of is dated 1993! This total rewrite contains bugfixed implementations of the existing SWIs (e.g. AddToDate can actually cope with more than 28 days!) but that’s for backwards compatibility, they’re not great APIs. The new SWIs do datetime conversions to various packed and integer representations, including _Now which returns number of days and number of centiseconds separately, which is often convenient. But it’d need the reverse functions too. It also contains the |
Steffen Huber (91) 1949 posts |
It took the Java guys up until Java 8 to implement something sensible. Nice to see that reinvent-the-wheel is alive and kicking everywhere. Anyone wanting to implement something sensible for RISC OS could do worse than looking at Joda-Time for inspiration. |
nemo (145) 2529 posts |
Thanks Steffen. The Chronologies are a good way of getting away from the Territory mess (and the fact that most of us only have the one). The Period is essentially Ordinals, DateTime is effectively 5-byte time but in ms. Much of the formatting and field access can already be done by Territory calls (not that they wouldn’t benefit from a nicer wrapper – eg DateUtils_WeekNo can already be got via %WK). So adding a set of Ordinals to a datetime clearly would be a useful function. The “display this date in Ethiopic form” is perhaps less important but would be nice. One of the best bits though is the date string parsing, which has always been massively restricted in RO. I had to go to quite some lengths in DateUtils to grok Module dates, as they’re not defined to be machine readable so could conceivably be in any language (it recognises 89 different month names because of that). |
Rick Murray (539) 13806 posts |
Uh… no… Not really. We are “leveraging” a system call to convert between one timezone and another because, well, because the time handling is crap and the system uses a five byte value that doesn’t exactly lend itself to simple operations like “add five hours”. The call normally translates between UTC (what OS_Word hands us) and whatever the local timezone is, however by supplying our own offset, we can make this SWI instead add or subtract arbitrary amounts of time, however we might need to consider also mucking around with the local timezone so that it isn’t in UTC if that’s not our own timezone. It’s difficult, but let’s explain.
So, it’s easy enough to read the time using If you provide the right flags to Here is proof. First, some code. REM >_dsttest DIM fivebyte% 5 DIM buf% 32 PRINT "TZ+0 NO DST test"'"================" *Configure NoDST *Configure TineZone +0 fivebyte%?0 = 3 SYS "OS_Word", 14, fivebyte% SYS "Territory_ConvertStandardDateAndTime", -1, fivebyte%, buf%, 32+(3<<30),,0 TO ,t% t%?0 = 13 PRINT "Raw system time = "+$buf% PRINT "Five byte time = "; PROCprintfive SYS "Territory_ConvertTimeFormats", -1, fivebyte%, fivebyte%, 3 + (1<<8) + (1 << 19), (100*60*60*12) PRINT "Added 12 hours = "; PROCprintfive PRINT '"TZ+1 DST test"'"=============" *Configure DST *Configure TimeZone +1 fivebyte%?0 = 3 SYS "OS_Word", 14, fivebyte% SYS "Territory_ConvertStandardDateAndTime", -1, fivebyte%, buf%, 32+(3<<30),,0 TO ,t% t%?0 = 13 PRINT "Raw system time = "+$buf% PRINT "Five byte time = "; PROCprintfive SYS "Territory_ConvertTimeFormats", -1, fivebyte%, fivebyte%, 3 + (1<<8) + (1 << 19), (100*60*60*12) PRINT "Added 12 hours = "; PROCprintfive END : DEFPROCprintfive FOR l% = 0 TO 4 PRINT ;fivebyte%?l%; IF l% < 4 THEN PRINT ", "; NEXT PRINT ENDPROC When run, this is what is output: *_dsttest TZ+0 NO DST test ================ Raw system time = 16:27:49 17-Apr-2023 Five byte time = 47, 138, 154, 150, 90 Added 12 hours = 47, 117, 220, 150, 90 TZ+1 DST test ============= Raw system time = 16:27:49 17-Apr-2023 Five byte time = 50, 138, 154, 150, 90 Added 12 hours = 50, 117, 220, 150, 90 * You can clearly see that in both cases, the five byte values are identical 1 regardless of whether we’re in DST or not, or in TimeZone +0 or +1. There should have been a two hour discrepancy if unintended things were going on. But since we’ve told the SWI to only apply our offset, then it has done that, to make a five byte time that is twelve hours later (than UTC, not local time). The reason I’m using Territory’s ConvertStandardDateAndTime instead of the OS one is because I can override the automatic conversion to print out the raw (UTC) system time. 1 The first byte will be different, it’s ticking centiseconds here; it’s the rest we look at… |
Rick Murray (539) 13806 posts |
Something sorely missing from RISC OS is the simple ability to output and parse various standard and commonplace date strings that can be found on-line. Like those used in cookies 1, 8601 (old and new) 2, and various RFC formats (for usenet headers, email headers, and so on) 3. And probably some others I’ve forgotten. 1 Monday, 17-Apr-23 18:55:00 CET (also as RFC850; the difficulty here is in understanding the timezone acronym) 2 2023-04-17 18:55:00 (old, space between) 3 Mon, 17 Apr 2023 18:55:00 +0100 (RFC822/2822/RSS) |
nemo (145) 2529 posts |
Unlike the other fields, the timezone %TZ is entirely at the whim of the Territory, which is awkward. In my notes I have proposed %MZ=month-as-number(0-11), %H2=hour-as-24(01-24) and %H1=hour-as-12(00-11), together with %IN, %IO, %I3, %IC and %IY for various Islamic calendar fields. One could imagine similar for other Chronologies. But numeric fields aside, the usual question persists: Whither the Territories. And I don’t know whether Muh, Saf, RaA, RaT, JuA, JuT, Raj, Shb, Ram, Sha, DaQ and DaH would make sense as 3-chr months for %I3 in the absence of Unicode. And Turkish month names are even more awkward. |
Rick Murray (539) 13806 posts |
Might I suggest we don’t need to be too concerned about Arabic dates until such time as FontManager can make a passable attempt to rendering the language? |