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 [3]
30 - m = mm-3
43,2 g x<0 m < 3 ?
21,0 GSB 0 => m = mm+12, y = yyyy-1
1 [1]
5 [5]
3 [3]
20 x
2 [2]
40 +
5 [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 [3]
6 [6]
5 [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 [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 [2]
5 [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 [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 [1]
7 [7]
2 [2]
1 [1]
1 [1]
1 [1]
9 [9]
40 + adjust for JD
43,21 g RTN
43,22,0 g LBL 0 x=mm-3, y=yyyy, z=dd
1 [1]
2 [2]
40 +
34 x<->y
1 [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 [7] compute day of week
42,9 f RMD CDW = (JDN mod 7) + 1
1 [1]
40 +
44,3 STO 3
1 [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 [1]
40 +
44,1 STO 1
45,3 RCL 3 compute week number
30 - CW = (CDY - CDW + 10) / 7
1 [1]
0 [0]
+ +
7 [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 [5]
2 [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 [3]
43,3 g x>y if (YYYY-1)-01-01 > Thursday
22,0 GTO 0 then CDW := 52; YYYY := YYYY-1;
5 [5] else CDW := 53; YYYY := YYYY-1;
3 [3]
44,2 STO 2
22,0 GTO 0
43,22,1 g LBL 1
5 [5]
3 [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 [3]
34 x<->y
43,3 g x>y if (YYYY+1)-01-01 < Thursday
22,0 GTO 0 then CW := 53;
1 [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 [1]
0 [0]
0 [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 [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 [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)
Comments are welcome
Hartmut
|