A tiny New Year's programming challenge

01012015, 04:51 PM
(This post was last modified: 01032015 06:49 AM by Dieter.)
Post: #1




A tiny New Year's programming challenge
The year has just begun  maybe it's time for a programming challenge that deals with dates and calendars, and even especially with the days around New Year. ;)
Instead of a particular date (e.g. "14.03.2014"), referring to a certain week of the year ("week 11/2014") often makes more sense, and so week numbers are commonly used in trade and business (at least over here in Europe). There is a international standard (ISO 8601) that defines the start of the first week of the year: it's the one with the major part (i.e. at least four days) belonging to January. So week #1 may start as late as 4 Jan or as early as 29 Dec of the previous year. Generally, weeks are defined as starting on Monday and ending on the following Sunday. More details can be found on Wikipedia. And here is your task: Write a program that accepts a valid Gregorian Date and returns the corresponding ISO week number, as well as the day number within that week. Some test cases: Code: 04 Jul 1979 => week 27/1979, day 3 The basic idea is very simple: determine the start of week #1, calculate the number of days between that Monday and the given date, and finally divide the result by 7. However, this may result in a negative value for the first days of a year, or it may return week #53 – which may or may not exist in that year. This is the "...challenging" part of the challenge. ;) Maybe your program even accepts any input that is valid for the current date format setting (i.e. dd.mmyyyy, mm.ddyyyy or even yyyy.mmdd), and the output is formatted according to the ISO standard (e.g. 1979W273). Of course calculators with date functions are very helpful here, that's why I would suggest using a 34s. Which does not mean that others cannot be used as well. ;) Enjoy! Dieter 

01012015, 06:00 PM
Post: #2




RE: A tiny New Year's programming challenge
For HP 48G, 49G & 49G+ the progs are available here:
http://www.hpcalc.org/hp49/utils/time/isodatev2.zip 

01022015, 07:17 AM
Post: #3




RE: A tiny New Year's programming challenge  
01022015, 10:29 AM
Post: #4




RE: A tiny New Year's programming challenge
Sorry, I made the library in 2004 & don't recollect how the calculation works  I'm not really interested in opening an old can of worms, but would be grateful for improvements & bug alerts.
While on this topic, why oh why didn't ISO count from 0 to 11 & 0 to 6? 

01022015, 10:16 PM
(This post was last modified: 01022015 11:31 PM by Gilles.)
Post: #5




RE: A tiny New Year's programming challenge
Hi
There is one error in your test cases : 01 Jan 2012 => week 52/2011, day 7 Here is an HP49/50 version Work both with the flag 42 set (dd/mm/yy) or not (mm/dd/yy) Date must be entered with the current HP50g format.Ex 19.081999 IsoWk > "1999W334" (flag 42 set jj.mmaaa) 12.312012 IsoWk > "2013W11" (flag 42 not set mm.jjaaaa) Code:


01032015, 06:58 AM
(This post was last modified: 01032015 07:10 AM by Dieter.)
Post: #6




RE: A tiny New Year's programming challenge
(01022015 10:16 PM)Gilles Wrote: There is one error in your test cases : Yes, of course. #) Sorry, just a typo. (01022015 10:16 PM)Gilles Wrote: Here is an HP49/50 version Great – thank you very much. I have to admit I never used any kind of RPL calculator, so it's a bit difficult for me to figure out how your program works. Would you mind explaining the algorithm, please? (01022015 10:16 PM)Gilles Wrote: Date must be entered with the current HP50g format.Ex Great. If the week was returned with two digits ("2013W011") the result would even be perfectly ISOcompliant. BTW I like the way you write the date formats with j, m and a. ;) Dieter, tt.mmjjjj 

01032015, 07:04 AM
Post: #7




RE: A tiny New Year's programming challenge
(01022015 10:29 AM)Gerald H Wrote: While on this topic, why oh why didn't ISO count from 0 to 11 & 0 to 6? I think it's simply because humans usually start counting at 1, not 0. The week is an ordinal number, so the first week is week 1, just as the third day in a week is day 3. I suppose it wouldn't be very helpful if the fifth day of week twenty would be described as week 19, day 4. ;) Dieter 

01032015, 01:24 PM
(This post was last modified: 01032015 05:17 PM by Gilles.)
Post: #8




RE: A tiny New Year's programming challenge
(01032015 06:58 AM)Dieter Wrote: I have to admit I never used any kind of RPL calculator, so it's a bit difficult for me to figure out how your program works. Would you mind explaining the algorithm, please? Hi dieter, I first tried to handle all the exceptions (negative result etc.) but it looks like marmalade ! So I change to handle all the cases in a single way. The general idea is : Giving a date d2 (dd.mmyyy or mm.ddyyyy format) : Calculate the first of january for y1, y , y+1 (the 1e6 step loop) for each year, calculte what day is the 1 january (mon, tue, wed ...). For this use the TSTR command and then add or substrat 3...3 days (the CASE serie)  with this, calculate what is the first day of the fisrt week of the year. For this use the DATE+ command  Then calculate the difference between d2 and the calculate fisrt day of the first week of the year. For this use the DDAYS command > If the result is negative, it is not the 'good' year > If it is positive, then the smallest delta is the good one (Delta) . You've get the correct year reference (y1) and the correct first day of first week of the year (d1) To finish:  Calculate the number of days between d1 and d2 (DDAYS)  Interger division by 7 (IDIV2 returns integer parts and remainder)  add 1 to each and you get the result Note that there is nothing special to handle dd.mmaaaa or mm.ddaaaa format. The 50G manage this (DATE+ DDAYS TSTR) and by chance (?) 1.012015 means the same thing in the 2 formats (first january) 

01032015, 06:20 PM
Post: #9




RE: A tiny New Year's programming challenge
(01032015 01:24 PM)Gilles Wrote: I first tried to handle all the exceptions (negative result etc.) but it looks like marmalade ! So I change to handle all the cases in a single way. The general idea is : Interesting approach. Just for comparison, I did it this way:
By the way: (01032015 01:24 PM)Gilles Wrote:  Interger division by 7 (IDIV2 returns integer parts and remainder) Yes, that's a very handy and useful command. Some time ago I suggested such a command that returns both the integer part and the remainder for the 34s (like DIV in x86 assembly language), but it did not make it into the final firmware. ;\ (01032015 01:24 PM)Gilles Wrote: Note that there is nothing special to handle dd.mmaaaa or mm.ddaaaa format. The 50G manage this (DATE+ DDAYS TSTR) and by chance (?) 1.012015 means the same thing in the 2 formats (first january) Yes, I used this trick as well. ;) On the other hand the 34s has a special DATE→ command that assembles year, month and day (given individually) into dd.mmyyyy or mm.ddyyyy or yyyy.mmdd, depending on the current date mode setting. Dieter 

01042015, 06:37 PM
(This post was last modified: 01042015 06:42 PM by Dieter.)
Post: #10




RE: A tiny New Year's programming challenge
(01012015 04:51 PM)Dieter Wrote: And here is your task: Write a program that accepts a valid Gregorian Date and returns the corresponding ISO week number, as well as the day number within that week. Just before week 2 starts, here is what I got with my 34s. Dates may be entered in dd.mmyyyy or mm.ddyyyy format. Code: LBL "KW" // "KW" is the common German abbreviation for "Kalenderwoche" ;) The subroutine at LBL 53 returns the last week# (zerobased) for a given year, i.e. 51 or 52. It checks whether the year starts with a Thursday or – if it is a leap year – with a Wednesday. These years have 53 weeks, otherwise 52. Dieter 

01052015, 10:55 AM
Post: #11




RE: A tiny New Year's programming challenge
Quote:The subroutine at LBL 53 returns the last week# (zerobased) for a given year, i.e. 51 or 52. It checks whether the year starts with a Thursday or – if it is a leap year – with a Wednesday. These years have 53 weeks, otherwise 52. Isn't it easier then to test Jan 1st of Y+1? If it's a Friday, Y has 53 weeks, else it's 52. No need for leap year testing. Werner 

01052015, 07:45 PM
(This post was last modified: 01052015 07:56 PM by Dieter.)
Post: #12




RE: A tiny New Year's programming challenge
(01052015 10:55 AM)Werner Wrote: Isn't it easier then to test Jan 1st of Y+1? If it's a Friday, Y has 53 weeks, else it's 52. No need for leap year testing. Sorry, but this does not cover all years with 53 weeks. Example: Y=2004. Here 1 Jan 2005 is a Saturday, not a Friday, but nevertheless 2004 had 53 weeks. The same is true for 2032 (1 Jan 2033 is a Saturday, but 2032 will have 53 weeks as well). Checking whether 1 January of the following year is a Friday means that the current year ends on a Thursday. This is only one of the two possible conditions for a 53weekyear. A common 53weekyear starts and ends on a Thursday. The other possible condition is a leap year starting on a Thursday and thus ending on a Friday. Which means that New Year of the following year is a Saturday, as shown in the two examples above. If a year has 53 weeks, it starts and/or ends on a Thursday. In common years both 1 Jan and 31 Dec are Thursdays. On the other hand, leap years with 53 weeks either start on a Wednesday (and therefore end on a Thursday – this case is covered by your suggestion), but they may as well start on a Thursday and end on a Friday. And this is what the routine checks: Is 1 Jan a Thursday OR (is it a leap year AND 1 Jan is a Wednesday). Cf. Wikipedia. Of course it is possible that the two tests can be implemented more elegantly. Any suggestions? Dieter 

01052015, 08:29 PM
Post: #13




RE: A tiny New Year's programming challenge
(01022015 07:17 AM)Dieter Wrote:(01012015 06:00 PM)Gerald H Wrote: For HP 48G, 49G & 49G+ the progs are available here: At long last the source for the 49G programme: GISO :: CK1&Dispatch BINT1 :: ID x003 DUP %20 DATE+DAYS % 10.0000001 %+ a%>$ BINT6 BINT9 SUB$ FPTR2 ^S>Z UNROTOVER DDAYS DUP %0< ITE :: DROPSWAP FPTR2 ^Z>R %1 DUP FPTR2 ^R>Z 3UNROLL % 1000000. %/ % 18.08 %+ ID x003 SWAPDROPSWAP DDAYS ; SWAPDROP SWAP FPTR2 ^Z>S $>ID SWAP COERCE BINT7 #/ #1+ #>$ DUPLEN$ #3= IT :: CHR_0 >H$ ; $>ID SWP1+ FPTR2 ^#>Z TWO{}N {}>TAG_ TWO{}N {}>TAG_ ; ; ISOG :: CK1&Dispatch BINT13 :: TAG>_ palparse DROP FPTR2 ^CK1Z FPTR2 ^Z>R SWAP DUPTYPETAG? NcaseTYPEERR TAG>_ palparse DROP FPTR2 ^CK1Z FPTR2 ^Z>R SWAP FPTR2 ^CK1Z FPTR2 ^Z>R 3UNROLL %1 SWAP % 1000000. %/ % 18.08 %+ ID x003 SWAPDROPSWAP %7 %* ROT %+ %1 DATE+DAYS ; ; x002 { "MO" "TU" "WE" "TH" "FR" "SA" "SU" } x003 :: DUP %100 %* %FP %100 %/ % 4.010001 %+ 2DUP DDAYS %7 %< ITE :: ID x002 3PICK %1 TIMESTR BINT3 1_#1SUB$ EQUALPOSCOMP BINT3 #> ; TRUE IT :: % .000001 % ; ID x002 OVER %1 TIMESTR BINT3 1_#1SUB$ EQUALPOSCOMP #1 UNCOERCE %CHS DATE+DAYS ; 

01052015, 09:21 PM
Post: #14




RE: A tiny New Year's programming challenge
@ Dieter: ah I see, I only went by your explanation ( that I quoted before), but I read it wrongly as nonleap years starting on a Thursday and leap years starting on a Wednesday ..


01062015, 04:11 PM
Post: #15




RE: A tiny New Year's programming challenge
As to making the check more elegant: all I have been able to come up with so far is to try and test for Mondays instead of Thursdays, if the DOW routine returns 0. for Mondays, that is.
A year has 53 weeks if and only if it starts or ends with a Thursday. A year that starts with a Thursday means 2.02yyyy will be a Monday. For a year that ends with a Thursday: Unfortunately, no xx.xxyyyy for x=3..12 (and Jan and Feb of y+1) are Mondays. No aa.bbyyyy exists for which both aa.bbyyyy and bb.aayyyy are Mondays (so that we can stay independent from the date setting). So I test 2.02yy+1 for a Tuesday instead.. Here's the two subroutines for 48/49/50 compatibles: Code: @ Day Of Week (as a number) Code: @ number of weeks in year Y Cheers, Werner 

01072015, 12:21 AM
Post: #16




RE: A tiny New Year's programming challenge
(01062015 04:11 PM)Werner Wrote: Here's the two subroutines for 48/49/50 compatibles: And here's a shorter and slightly more elegant version for the 34s that replaces the original routine at label 53. It reuses your idea of emulating a logical OR by a simple multiplication. Code: LBL 53 // input: year Since local flags are initially cleared, the CF.01 in the second line may even be omitted. Dieter 

01072015, 02:55 AM
Post: #17




RE: A tiny New Year's programming challenge  
01072015, 04:50 AM
Post: #18




RE: A tiny New Year's programming challenge
(01072015 02:55 AM)walter b Wrote: So far, I thought a multiplication is equivalent to a logical AND. What did I miss? De Morgan's laws 

01072015, 06:24 AM
Post: #19




RE: A tiny New Year's programming challenge
(01072015 02:55 AM)walter b Wrote:(01072015 12:21 AM)Dieter Wrote: It reuses your idea of emulating a logical OR by a simple multiplication. Ok, seems I forgot something I knew 35 years ago. I've to apologize for my bad memory. d:) 

01072015, 08:19 AM
Post: #20




RE: A tiny New Year's programming challenge
Dieter: what's wrong with this? My first ever WP34S try! And no fiddling with flags.
Code: LBL 53 

« Next Oldest  Next Newest »

User(s) browsing this thread: 1 Guest(s)