Territory_ConvertTimeFormats
John WILLIAMS (8368) 495 posts |
I am trying to adjust a time (actually a date) by subtracting a number of hours in BASIC. I create a daily file name in yyyymmdd format for use overnight, but if I create the file early next morning because I’m late to bed, I want it to be named the previous day, not the current. My problem is that it becomes very complicated if I need (as I do) to span the day change at midnight, becoming even more so if I am near the end/start of a month. I haven’t even got to considering how complicated it would become if It was New Year! And DST! Well, isn’t that what Territory is about? I could just cheat and temporarily use a (US Central Time?) timezone whilst I create my filename, for example, I expect, but that seems a bit defeatist! According to my SH manual, SYS"Territory_ConvertTimeFormats" should do what I need, where it suggests that bit 19 of R3, when set, will allow the result in R4 to be the time in centiseconds. However, the Wiki says (31/08/2017, Jeffrey Lee), of Territory Manager 0.47, this bit is still reserved. We are currently at 0.58. Is the SH manual a fiction, or is the Wiki just too out-of-date? Either way my plan, to take the local 5-byte time number, subtract a number of centiseconds corresponding to my adjustment, then use this SWI to put the new value back does not seem to work! I’m trying various values of R3 to see if they make any difference (by REMming out alternative lines, as I don’t really understand what the higher bits do/how they interact) but this code seems to relentlessly return the same 5-byte local time I give it to start with. I’ve omitted the boring bits where I DIM memory and read the 5-byte time using OS_Word,14,block% – I do already have some “gobbledegook ASCII” at block% representing the centisecond timestamp!
Should it work? What hideous error am I making? Something very silly, I’ve no doubt. |
Rick Murray (539) 13850 posts |
Your request prompted me to dig up the code where I wanted something similar. I… took an entirely different approach, after deciding that sorting out all the months and such would be a pain. Have fun! ;) DIM buffer% 255 buffer%?64 = 3 SYS "OS_Word", 14, buffer%+64 SYS "Territory_ConvertTimeToOrdinals", -1, buffer%+64, buffer% yy% = buffer%!&18 mm% = buffer%!&14 dd% = buffer%!&10 jd% = (1461*(yy%+4800+(mm%-14)/12))/4+(367*(mm%-2-12*((mm%-14)/12)))/12-(3*((yy%+4900+(mm%-14)/1 /100))/4+dd%-32075 PRINT "Actual date: "+STR$(yy%)+"/"+RIGHT$("0"+STR$(mm%), 2); PRINT "/"+RIGHT$("0"+STR$(dd%), 2) REM Fiddle if early morning (before 4am) IF (buffer%!&0C < 4) THEN jd% -= 1 REM Now back again jd% += 68570 N% = 4 * jd% / 146097 jd% = jd% - (146097 * N% + 3) / 4 Y% = 4000 * (jd% + 1) / 1461001 jd% = jd% - 1461 * Y% / 4 + 31 M% = 80 * jd% / 2447 D% = jd% - 2447 * M% / 80 jd% = M% / 11 M% = M% + 2 - 12 * jd% Y% = 100*(N% - 49) + Y% + jd% PRINT "Using date : "+STR$(Y%)+"/"+RIGHT$("0"+STR$(M%), 2); PRINT "/"+RIGHT$("0"+STR$(D%), 2) |
Alan Adams (2486) 1149 posts |
And another approach
|
nemo (145) 2552 posts |
Crikey. It ought to be quite simple – just convert to Ordinals, manipulate them, and convert back:
[edited for twice hitting the wrong key] FTR, ConvertTimeFormats only exists in the RO5 fork, whereas the above is RO3+. |
John WILLIAMS (8368) 495 posts |
Thank you Rick. But I think I’m just going to use the TimeZone keyword to set the time 6 hours back (or whatever I or the user choose) a set number of hours, do the filename generation, then set it back again to what it was. I’m using a real-time clock as the application requires “stand-alone” capability, but I don’t think my suggested calculation is going to make a significant difference to the time-keeping accuracy. My application is a Nocturia Incidence Recorder, probably for use by gentlemen (mainly) of (perhaps) a certain age or maturity. Punch a button on your way to the facility and the results are presented to you nicely formatted for future reference in a dated file. However, I’d still like to know why reading the centisecond clock, subtracting a number of centiseconds, then writing it back doesn’t appear to do the trick as I imagined it would with the multi-purpose system call in the title. And it may be that the Wiki needs updating for this call. |
Alan Adams (2486) 1149 posts |
I couldn’t see anywhere in your example that you HAD subtracted the time. This might be a case where the boring bits are important. |
John WILLIAMS (8368) 495 posts |
The takeaway bit is in R4. Which is where the SH entry says it should be if R3 bit 19 is set. And which the Wiki doesn’t mention. |
Alan Adams (2486) 1149 posts |
|
John WILLIAMS (8368) 495 posts |
As I believe I mentioned, the Wiki entry was 2017,and I deduce that the StrongHelp entry may be for a later version, and it is that which refers to the bit 19 set option giving the alternative option of entering a centisecond value to adjust the result. This may be based on wishful thinking on someone’s part, or the Wiki entry you quote may be out-of-date, the version number having gone up an impressive 0.11 since that was written – or 11 changes or developments made. I expect that the SH manual has some basis in fact, whilst one must allow that some inaccuracies may be present. I apologise if my inability to express myself clearly is causing difficulties – I do try my best! |
Rick Murray (539) 13850 posts |
The Wiki The correct place to look mentions it: https://gitlab.riscosopen.org/RiscOS/Sources/Internat/Territory/TerritoryManager/-/blob/master/s/SWIs#L1035 This is followed by the code that makes it happen: https://gitlab.riscosopen.org/RiscOS/Sources/Internat/Territory/TerritoryManager/-/blob/master/s/SWIs#L1117 Before you say anything, do remember that the actual printed documentation is impossibly old, and everything that has come subsequently is mostly through various volunteer efforts so things may be missed or incomplete (well, the same is true of published documents, but you’d hope there was some sort of review process there). As such, the only proper place to look to see what is and isn’t supported is…the code that makes it happen. What flags are you actually passing to the SWI there? |
Colin Ferris (399) 1818 posts |
Back along on ships – we were sent pages of updates to our books – to be glued in or written changes. Mind you Ricks RO 2 updates mights run to several pages :-) |
John WILLIAMS (8368) 495 posts |
At the very top of the thread, many ’phone screens away, I stated that I had devised three format specifiers/flag sets/numbers to put in R3. I displayed these in hex because I do find binary a bit unwieldy. These were: &80101 – the &0101 to set the lower 2 bits to specify the local 5-byte time input and output, and the leading “8” setting bit 19 &C0101, &E0101, the leading “C” and “E” fiddling with bits 18 and 17 because, being a bear of little brain, I couldn’t see if they were necessary or not for my purpose (suck it and see principle). I used SciCalc to get my head round this travail, but may well have still cocked-up; 19 is a lot when one’s counting zeros! I even made a little bit-counting matrix in Draw, remembering to start at zero on the right instead of one. I put all three alternatives in a sequence in my code to keep them safe and REMmed some out to check them all. I won’t duplicate the code again here – it is still at the very start of the thread. Thank you for sorting out the Wiki entry. I should have asked you in the first place ;-| Whilst I’m grateful to everyone who suggested or posted code showing “mucking about with ordinals”, I resisted that myself as “that’s what computers are good at!”. After all, this basic manipulation of the clock by hour(s) and minutes is exactly what “Territory” is about if you exclude the “alphabet” and other bits Rick hates. Sorry and glad to have drawn you in, Rick, both at the same time! No RISC OS capability for a few days – plasterer coming tomorrow, need bigger house to move things into! |
Alan Adams (2486) 1149 posts |
If I was doing that in BASIC I would use
That way I can see that I’m using 1 as both the input and output, and setting bit 19. |
Alan Adams (2486) 1149 posts |
Nemo’s solution is typically terse, and also quite elegant. I wonder however what the SWI does if an ordinal goes out of range. For example, it’s one hour after midnight. The value for hour will be 1. Then you subtract 3 to go back 3 hours, and the value becomes -2. For the example to work the Territory call would need to adjust the hour and day (and potentially month and year as well – Think 1-Jan-2023:01:00:00 minus 3 hours). Does it do that? For this bear of little brain, it would seem that it might work if: Each ordinal is scaled, using signed arithmetic, and added into the 5-byte result, again signed. What I can’t quite see is how that would result in the unsigned 5-byte result that is a time. I do periodically curse whoever dreamed up a 40-bit time for a 32-bit system… |
Andrew Conroy (370) 740 posts |
I would recommend !BitField from !Store for looking at things like this, it makes it much clearer what bits are set. |
John WILLIAMS (8368) 495 posts |
That looks like a useful notation if I can get my head around it; thank you!
Thank you, Andrew, I’ll have a look. |
Martin Avison (27) 1494 posts |
It certainly is. But I think it is also wrong, because in His solution intrigued me, as I had never thought of using
Personally I prefer the (1<<19) in the code, as that avoids having to lookup what is in the code.
Like the John, I have tried |
Fred Graute (114) 645 posts |
Yes, but there needs to be a conversion from local time to UTC (or vice versa) for the R4 difference to be applied (as stated in the source). So, |
Alan Adams (2486) 1149 posts |
Experimenting with Territory_ConvertDateAndTime, I discovered that the largest value of 5-byte time which worked was &fe ff ff ff ff, producing a date in 2247 – well beyond anything I might be worried about. However it does seem to show that the different Territory functions have different upper limits – nasty. I also tried Martin’s example above, but with R3=&0301, which should I think mean “the input is in BST while the output needs to be in UTC”. The input is identical to the output. This suggests the subtract function doesn’t do anything even in the original form. This is on RO5.29, Dec 2022 version. |
Rick Murray (539) 13850 posts |
I think that the call does a certain amount of sanity checking, but that this perhaps shouldn’t be relied upon. Certainly, unless it is a documented side effect, any subsequent release could “do it differently” or perhaps not at all. I had noticed it works a while back, but I don’t like relying in side effects if I can help it.
Indeed. I was reading/writing earlier on my phone, so didn’t have an easy way to convert hex to bits.
Simple, possibly dumb, question – but what are you providing as input and output formats? You do realise that if you’re going UTC to UTC, or local to local, then there’s no offset going to be applied regardless of what any other flags might suggest. I think you’ll want to go UTC to local, and specify the offset as you’re doing. Edit: Beaten by Fred. I should write more succintly… |
Rick Murray (539) 13850 posts |
The centisecond clock, with the least significant byte at +0 and the most significant at +4, is something else Arthur (then RISC OS) inherited from the BBC MOS. |
John WILLIAMS (8368) 495 posts |
So I may assume that Fred’s observations solve the problem. Thank you. I will try it in a day or so when I get my life back. It is a more elegant method for what I want than fiddling with ordinals or reconfiguring timezone temporarily, but I still can’t say I understand why it only works with the conversion. I will try harder when my furniture redispositioning is over for good. Thank you all for your contributions. |
Rick Murray (539) 13850 posts |
This works: DIM fiveone% 5 DIM fivetwo% 5 DIM buffer% 32 REM Read 5 byte time fiveone%?0 = 3 SYS "OS_Word", 14, fiveone% REM Convert as if UTC to local, only adding 12 hours SYS "Territory_ConvertTimeFormats", -1, fiveone%, fivetwo%, 3+(1<<8)+(1<<19), (100*60*60*12) REM Make it a string to print SYS "OS_ConvertStandardDateAndTime", fivetwo%, buffer%, 32 TO ,t% t%?0 = 13 PRINT $buffer% It’s simpler than that Julian date stuff I wrote earlier. ;) |
Andrew Conroy (370) 740 posts |
I agree, that’s better for writing the code, but for visualising the bitfield, I find it easier to see it as a collection of bits on screen than imaging it in my head. Especially when someone posts code with magic values and you’re trying to work out which bits they’ve set! |
Andrew Conroy (370) 740 posts |
Just tried a quick BASIC loop to see the speed effect setting magic values has rather than calculated bitfields. A tight FOR-NEXT loop of setting a variable to a magic value (&8203) 1million times on a Pi 3B+ took 19cs, but calculating the value for &8203 by shifting 4 lots of 1s a million times took 75cs. |