RE: A tiny New Year's programming challenge - Dieter - 01-07-2015 01:46 PM
(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.
Thank you for your suggestion!
Dieter
RE: A tiny New Year's programming challenge - wynen - 01-22-2015 01:50 PM
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
RE: A tiny New Year's programming challenge - Damien - 01-22-2015 11:24 PM
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
RE: A tiny New Year's programming challenge - Dieter - 01-23-2015 08:25 PM
(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
RE: A tiny New Year's programming challenge - Dieter - 01-23-2015 08:39 PM
(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
RE: A tiny New Year's programming challenge - Damien - 01-23-2015 09:47 PM
(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.
RE: A tiny New Year's programming challenge - Dieter - 01-23-2015 10:07 PM
(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
|