A tiny New Year's programming challenge
01-07-2015, 01:46 PM (This post was last modified: 01-07-2015 02:00 PM by Dieter.)
Post: #21
 Dieter Senior Member Posts: 2,397 Joined: Dec 2013
RE: A tiny New Year's programming challenge
(01-07-2015 08:19 AM)Werner Wrote:  Dieter: what's wrong with this? My first ever WP34S try! And no fiddling with flags.

There's nothing wrong with it – it works just as well. Your routine checks if the year starts or ends on a Thursday. Which is equivalent to testing if 2 Feb is a Monday OR 2 Feb of the next year is a Tuesday. Your program evaluates this as

(weekday(2.2.yyyy) – 1)  *  (weekday(2.2.yyyy+1) – 2)

After omitting the initial CF.01 in my routine, both of our versions require 19 steps. Using NOT instead of SIGN +/– is a good idea – it will save another step. ;-)

I should add that I also wanted to use as few calls to date routines as possible in order to speed up the program for calculators that do not offer such functions, so that a single call of WDAY would be preferred. But for such calculators maybe a completely different approach would make more sense.

Dieter
01-22-2015, 01:50 PM
Post: #22
 wynen Junior Member Posts: 12 Joined: Sep 2014
RE: A tiny New Year's programming challenge
I suppose, I'm a bit late for a "New Year's" programming challenge, but I want to contribute a HP-16C program to convert calender date representations.

My solution uses a subroutine to convert a (proleptic) Gregorian Calender date YYYY-MM-DD to a Julian Day Number (i.e. the Julian Date as of YYYY-MM-DDT12:00Z).
Code:
 43,22,D     g LBL D     x=yyyy, y=mm, z=dd 34          x<->y       x=mm, y=yyyy, z=dd 3            30          -           m = mm-3 43,2        g x<0       m < 3 ? 21,0        GSB 0       => m = mm+12, y = yyyy-1 1            5            3            20          x    2            40          + 5            10          ./.         x=(153m+2)/5, y=y, z=d, t=? 34          x<->y       x=y, y=(153m+2)/5, z=d, t=? 33          Rv          x=(153m+2)/5, y=d, z=?, t=y 40          +           x=(153m+2)/5+d, y=?, z=y, t=y 3            6            5            43,33       g R^        x=y, y=365, z=(153m+2)/5+d, t=? 20          x 43,36       g LSTx      x=y, y=365*y, z=(153m+2)/5+d, t=? 4            10          ./.         x=y/4, y=365*y, z=(153m+2)/5+d, t=? 40          + 43,36       g LSTx      x=y/4, y=365*y+y/4, z=(153m+2)/5+d, t=? 2            5            10          ./.         x=y/100, y=365*y+y/4, z=(153m+2)/5+d, t=? 30          - 43,36       g LSTx      x=y/100, y=365*y+y/4-y/100, z=(153m+2)/5+d, t=? 4            10          ./.         x=y/400, y=365*y+y/4-y/100, z=(153m+2)/5+d, t=? 40          + 40          +           x=d+(153m+2)/5+365*y+y/4-y/100+y/400 1            7            2            1            1            1            9            40          +           adjust for JD 43,21       g RTN 43,22,0     g LBL 0     x=mm-3, y=yyyy, z=dd 1            2            40          +    34          x<->y 1            30          - 34          x<->y 43,21       g RTN       x=mm+12 y=yyyy-1

ISO 8601 calender date representations:
• Calendar date: YYYY-MM-DD
where YYYY represents a calendar year, MM the ordinal number of a calendar month within the calendar year, and DD the ordinal number of a calendar day within the calendar month
• Ordinal date: YYYY-DDD
where YYYY represents a calendar year and DDD the ordinal number of a calendar day within the calendar year
• Week date: YYY-Www-D
where YYYY represents a calendar year, W is the week designator, ww represents the ordinal number of a calendar week within the year, and D represents the ordinal number of a calendar day within the calendar week.

Convert calendar date to ordinal date or week date using the Julian Day Number JDN(YYYY-MM-DD).
• Julian Day Number
if mm > 2 then m := mm-3; y:=yyyy else m := mm+12; y := yyyy-1 endif
JDN(yyyy-mm-dd) := 365*y + y/4 - y/100 + y/400 + (153*m+2)/5 + dd + 1721119
• Ordinal number of a calendar day within the calendar week (Calendar day of the week, CDW)
CDW = (JDN(yyyy-mm-dd) mod 7) + 1
• Ordinal number of a calendar day within the calendar year (Calender day of the year, CDY)
CDY = JDN(yyyy-mm-dd) - JDN(yyyy-01-01)
• Ordinal number of a calendar week within the year (Calender week, CW)
CW = [(CDY - CDW + 10) / 7]
The expression (CDY-CDW+10) is constant for a calender week (1 <= CDW <= 7) and increments by 7 for the next week.
For CW = 1 there is 7 <= (CDY - CDW + 10) <= 13
For CDY = 1 (1st of January): If CW = 1 then CDW <= 4 (Thursday)
Special cases:
• (CDY - CDW + 10) / 7 == 0:
the calendar day belongs to calendar week 52 or 53 of the preceding year.
CW = 53 if the 1st of January of the preceding year is in calendar week 1 of the preceding year i.e. is Monday to Thursday, otherweise CW = 52.
• (CDY - CDW + 10) / 7 == 53:
the calendar day belongs to calendar week 1 of the next year, if the 1st of January of the next year is Tuesday to Thurday. Otherwise it is really CW 53.
Code:
 43,22,C     g LBL C 44,0        STO 0       calendar year for ordinal date (YYYY-DDD) 44,5        STO 5       calender year for week date (YYYY-Www-D) 21,d        GSB D       compute Julian Day Number 44,4        STO 4 7                    compute day of week 42,9        f RMD       CDW = (JDN mod 7) + 1 1                40          + 44,3        STO 3 1            36          ENTER 36          ENTER 45,0        RCL 0 21,d        GSB D       compute Julian Date of 1st of January 45,4        RCL 4       compute day of year 34          x<->y       CDY = JDN(yyyy-mm-dd) - JDN(yyyy-01-01) + 1 30          - 1            40          + 44,1        STO 1        45,3        RCL 3       compute week number  30          -           CW = (CDY - CDW + 10) / 7 1            0            +           + 7            10          ./. 44,2        STO 2 43,30       g x>0       special calculation for CW=0? 22,1        GTO 1       No, check for CW 53 5            2            44,2        STO 2       assume CW =52 43,4,2      g SF 2      compute Calender Day of the Week 21,2        GSB 2       for the 1st of January of the preceding year 3            43,3        g x>y       if (YYYY-1)-01-01 > Thursday  22,0        GTO 0       then CDW := 52; YYYY := YYYY-1; 5                    else CDW := 53; YYYY := YYYY-1; 3            44,2        STO 2 22,0        GTO 0 43,22,1     g LBL 1 5            3            43,0        g x<>y      special calculation for CW=53? 22,0        GTO 0       No, display result 43,5,2      g CF 2      compute Calender Day of the Week 21,2        GSB 2       for the 1st of January of the next year 3            34          x<->y 43,3        g x>y       if (YYYY+1)-01-01 < Thursday 22,0        GTO 0       then CW := 53; 1                    else CW := 1; YYYY := YYYY+1; 44,2        STO 2 45,0        RCL 0 40          +  44,0        STO 5        43,22,0     g LBL 0     show results 45,0        RCL 0       calendar year (YYYY) 1            0            0            0            20          x           (YYYY000) 45,1        RCL 1       Calender Day of the Year (1...365/366) 40          +           ISO 8601 ordinal date: YYYYDDD 45,3        RCL 3       Calender day of the Week (1=Mon,...,7=Sun) 45,2        RCL 2       Calender Week of the Year (1..52/53) 45,5        RCL 5       Calender Year (corrected for Calender Week) 43,21       g RTN              43,22,2     g LBL 2     Compute Calender Day of Week for the 1st of January 1                    of the preceding year (flag 2 set) 36          ENTER       or the next year (flag 2 cleared) 36          ENTER        43,6,2      g F? 2 49          CHS 45,0        RCL 0       x = YYYY 40          +           x = (Flag 2 set) ? YYYY-1 : YYYY+1 43,6,2      g F? 2 44,0        STO 5       Store YYYY-1 21,d        GSB D       JDN(x-01-01) 7            42,9        f RMD       CDW (0=Mon,...,3=Thu,...,6=Sun) 43,21       g RTN Registers: R0 = calendar year (YYYY) R1 = calendar day of the year (DDD) R2 = calendar week (ww) R3 = calendar day of the week (D) R4 = julian day number R5 = calendar year for week date (R0+-1)

Usage:
DEC
{DD}
ENTER
{MM}
ENTER
{YYYY}
GSB C

Display result:
YYYY (corrected for calender week)
Rdown
ww (calender week: 1-53)
Rdown
D (weekday (1=Mon,...,7=Sun)
Rdown
YYYYDDD (ISO 8601 ordinal date)

Hartmut
01-22-2015, 11:24 PM (This post was last modified: 01-23-2015 10:32 AM by Damien.)
Post: #23 Damien Junior Member Posts: 29 Joined: Dec 2013
RE: A tiny New Year's programming challenge
Hi everyone !

Something for HP PRIME:
Code:
 //-------------------------------------- // Convert gregorian calendar dates // YYYY.MMDD into yyyy-Www-d  // according to ISO 8601 // V0.1 (2015-W04-4) //-------------------------------------- EXPORT ISOWeekDate(date)  BEGIN   LOCAL year,day,JDn;   LOCAL ISOWeekNb,ISOd,ISOYear; // cut date YYYY.MMDD   year:=IP(date); // YYYY   day:=IP(FP(FP(date)*100)*100); // DD   ISOYear:=IP(date); // YYYY // Find julian day number at noon // from the gregorian date YYYY.MMDD   JDn:=DateG2JJ(date); // Find day number according to ISO8601 // (Mo=1,Tue=2,...,Sun=7)   ISOd:=(JDn MOD 7)+1; // Find week number according to ISO8601 // (1≤WeekNb≤53)   ISOWeekNb:=ISOWeekNum(JDn); // Find year according to ISO8601  // - for 'normal' week: 2≤Week≤51 // - for 'pivotal' week:1,52,53   IF 1<ISOWeekNb<52 THEN    ISOYear:=IP(date);   ELSE // possible week transitions between  // year N and N+1 //+---------+--+--+--+--+--+--+--+-+------------- //|Monday   |22|23|24|25|26|27|28|1| //|Tuesday  |23|24|25|26|27|28|29|2|    THE //|Wednesday|24|25|26|27|28|29|30|3|LAST WEEK OF //|Thursday |25|26|27|28|29|30|31|4|  YEAR N-1 //|Friday   |26|27|28|29|30|31|01|5| //|Saturday |27|28|29|30|31|01|02|6|(WEEK 52, 53) //|Sunday   |28|29|30|31|01|02|03|7| //+---------+--+--+--+--+--+--+--+-+------------- //|Monday   |29|30|31|01|02|03|04|1| //|Tuesday  |30|31|01|02|03|04|05|2|    THE //|Wednesday|31|01|02|03|04|05|06|3|FIRST WEEK OF //|Thursday |01|02|03|04|05|06|07|4|   YEAR N //|Friday   |02|03|04|05|06|07|08|5| //|Saturday |03|04|05|06|07|08|09|6|  (WEEK 1) //|Sunday   |04|05|06|07|08|09|10|7| //+---------+--+--+--+--+--+--+--+-+------------- //                 ⇳ // Now lets translate this into // some (many) lines of code    IF ISOWeekNb==1 THEN // first week ?     IF ISOd==1 THEN // Monday ?      IF 29≤day≤31 THEN        ISOYear:=IP(date)+1; // YYYY+1      ELSE       IF 1≤day≤4 THEN         ISOYear:=IP(date); // YYYY       END;      END;     END; // Monday      IF ISOd==2 THEN // Tuesday ?      IF 30≤day≤31 THEN        ISOYear:=IP(date)+1; // YYYY+1      ELSE       IF 1≤day≤5 THEN         ISOYear:=IP(date); // YYYY       END;      END;     END; // Tuesday     IF ISOd==3 THEN // Wednesday ?      IF day==31 THEN       ISOYear:=IP(date)+1; // YYYY+1      ELSE       IF 1≤day≤6 THEN        ISOYear:=IP(date); // YYYY       END;       END;     END; // Wednesday     IF ISOd==4 THEN // Thursday ?      IF 1≤day≤7 THEN       ISOYear:=IP(date); // YYYY      END;     END; // Thursday     IF ISOd==5 THEN // Friday ?      IF 2≤day≤8 THEN       ISOYear:=IP(date); // YYYY       END;     END; // Friday     IF ISOd==6 THEN // Saturday ?       IF 3≤day≤9 THEN       ISOYear:=IP(date); // YYYY      END;     END; // Saturday     IF ISOd==7 THEN // Sunday ?      IF 4≤day≤10 THEN       ISOYear:=IP(date); // YYYY      END;     END; // Sunday     ELSE // Week 1      IF 52≤ISOWeekNb≤53 THEN // last week ?       IF ISOd==1 THEN // Monday ?        IF 22≤day≤28 THEN         ISOYear:=IP(date); // YYYY        END;       END; // Monday       IF ISOd==2 THEN // Tuesday ?        IF 23≤day≤29 THEN         ISOYear:=IP(date); // YYYY        END;       END; // Tuesday       IF ISOd==3 THEN // Wednesday ?        IF 24≤day≤30 THEN         ISOYear:=IP(date); // YYYY        END;       END; // Wednesday       IF ISOd==4 THEN // Thursday ?        IF 25≤day≤31 THEN         ISOYear:=IP(date); // YYYY        END;       END;       IF ISOd==5 THEN // Friday ?        IF 26≤day≤31 THEN         ISOYear:=IP(date); // YYYY        ELSE         IF day==1 THEN          ISOYear:=IP(date)-1; // YYYY-1         END;        END;       END;       IF ISOd==6 THEN // Saturday ?        IF 27≤day≤31 THEN         ISOYear:=IP(date); // YYYY        ELSE         IF 1≤day≤2 THEN           ISOYear:=IP(date)-1; // YYYY-1         END;        END;       END;       IF ISOd==7 THEN // Sunday ?        IF 28≤day≤31 THEN         ISOYear:=IP(date); // YYYY        ELSE         IF 1≤day≤3 THEN           ISOYear:=IP(date)-1; // YYYY-1         END;        END;       END;  // Sunday ?      END;  // 52≤week≤53 ?     END;  // week 1 ?     END;  // 2≤week≤51 ? // ( Phew ! Thanks CUT/COPY/PAST ! ) //  TEXT Formatting    IF ISOWeekNb<10 THEN     RETURN ISOYear+"-W0"+ISOWeekNb+"-"+ISOd;    ELSE     RETURN ISOYear+"-W"+ISOWeekNb+"-"+ISOd;    END; END; // Begin //---------------------------------------------------- // Convert calendar (Gregorian) date // to julian day number JDn at noon // aaaa.mmjj => JDn // e.g. 2000.0101 => 2451545 (J2000) //---------------------------------------------------- DateG2JJ(date) // for date ≥ oct 15 1582 (2299161) BEGIN  LOCAL year,month,day;  LOCAL cnt,diz; // Cut the date YYYY.MMDD into sub parts   year:=IP(date); // YYYY   month:=IP(100*FP(date)); // MM   day:=IP(FP(FP(date)*100)*100); // DD // Move the beginning of the year to // March 1st (adding 1 day, e.g. feb 29th // becomes easier if at the end)   IF month<3 THEN    year:=year-1;    month:=month+12;   END; // Cut the year into parts // (Needed for converting Gregorian // calendar dates to JDN)   cnt:=IP(year/100); // [YY]YY   diz:=IP(year-100*IP(year/100)); //YY[YY] // julian day number at noon // from gregorian date YYYY.MMDD   RETURN IP((146097*cnt+6884480)/4)          +IP(1461*diz/4)          +IP((153*month-457)/5)          +day-1; END; //---------------------------------------------------- // Return the week number [1 - 52 sometimes 53]  // according to ISO 8601 from the julian day number  // (JDn≥2299161) //---------------------------------------------------- ISOWeekNum(JD) BEGIN   LOCAL d4;   d4:=(JD+31741-(JD MOD 7)) MOD 146097        MOD 36524 MOD 1461;   RETURN IP(((d4-IP(d4/1460)) MOD 365          +IP(d4/1460))/7+1); END;
Convert calendar date YYYY.MMDD to ISO 8601 date yyyy-Www-d.

e.g. 2013.1231 => 2014-W01-2

Regards,

Damien
01-23-2015, 08:25 PM (This post was last modified: 01-23-2015 08:32 PM by Dieter.)
Post: #24
 Dieter Senior Member Posts: 2,397 Joined: Dec 2013
RE: A tiny New Year's programming challenge
(01-22-2015 01:50 PM)wynen Wrote:  I suppose, I'm a bit late for a "New Year's" programming challenge, but I want to contribute a HP-16C program to convert calender date representations.

Thank you very much for your contribution. I do not have access to a 16C, so I cannot try your program. I assume it is based on integer arithmetics. Does it also work for negative (B.C.) years?

(01-22-2015 01:50 PM)wynen Wrote:  My solution uses a subroutine to convert a (proleptic) Gregorian Calender date YYYY-MM-DD to a Julian Day Number (i.e. the Julian Date as of YYYY-MM-DDT12:00Z).
(...)
• Julian Day Number
if mm > 2 then m := mm-3; y:=yyyy else m := mm+12; y := yyyy-1 endif
JDN(yyyy-mm-dd) := 365*y + y/4 - y/100 + y/400 + (153*m+2)/5 + dd + 1721119

I think it's not mm+12 in the "else" branch, but mm+9. This is also what your program calculates: it first evaluates mm–3 and, if this is <0 (i.e. mm=1..2) it adds 12 back, giving in total mm+9.

(01-22-2015 01:50 PM)wynen Wrote:
• Ordinal number of a calendar day within the calendar year (Calender day of the year, CDY)
CDY = JDN(yyyy-mm-dd) - JDN(yyyy-01-01)

+1, I would say, or use JDN(yyyy-01-00). Otherwise 1 Jan is day 0.

(01-22-2015 01:50 PM)wynen Wrote:
• Ordinal number of a calendar week within the year (Calender week, CW)

I think I''ll have to take a closer look at that. Have you tried the examples in my initial post?

Dieter
01-23-2015, 08:39 PM
Post: #25
 Dieter Senior Member Posts: 2,397 Joined: Dec 2013
RE: A tiny New Year's programming challenge
(01-22-2015 11:24 PM)Damien Wrote:  Something for HP PRIME:

Thank you for this elaborate version with a completely different approach, translating week tables into a more than complex if-then-else sequence. The formula in the weeknumber routine looks interesting as well.

Dieter
01-23-2015, 09:47 PM (This post was last modified: 01-23-2015 10:10 PM by Damien.)
Post: #26 Damien Junior Member Posts: 29 Joined: Dec 2013
RE: A tiny New Year's programming challenge
(01-23-2015 08:39 PM)Dieter Wrote:
(01-22-2015 11:24 PM)Damien Wrote:  Something for HP PRIME:

Thank you for this elaborate version with a completely different approach, translating week tables into a more than complex if-then-else sequence. The formula in the weeknumber routine looks interesting as well.

Dieter

Thanks Dieter,

the first time i saw this formula, I immediately thought to the GREAT WP34s and its JDN function.

the weeknumber formula was found here:
http://www.auduteau.net/calendar/cal5.shtml ( in french Sorry ! )
But it seems to be the translation of (in english):
http://www.tondering.dk/claus/cal/week.php
(unfortunately where the weeknumber formula has disappeared... And has been remplaced by another formula (the author trial ? - That in some cases don't gives the good answer).

Regards,

Damien.
01-23-2015, 10:07 PM
Post: #27
 Dieter Senior Member Posts: 2,397 Joined: Dec 2013
RE: A tiny New Year's programming challenge
(01-23-2015 09:47 PM)Damien Wrote:  the weeknumber formula was found here:
http://www.auduteau.net/calendar/cal5.shtml ( in french Sorry ! )

No need to apologize. The formula indeed looks promising. I tried some test cases with the 34s and the results look fine. However, a proof or at least an explanation how it works would be nice.

Dieter
 « Next Oldest | Next Newest »

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