29
\$\begingroup\$

So, now that it's 2015, and a bunch of answers from last year's puzzle are now starting to produce invalid output, it's time for a question involving the number 2015.

Except... why? Wouldn't you like it if your date-based answers to last year's problem were to stay valid? Why don't we change our calendar so that it's never 2015, and we simply continue living in 2014, forever and ever?

Let's define a new date notation, called Eternal 2014 notation, as follows:

  • For dates 2014 and before, the dates will be the same as in the proleptic Gregorian calendar.
  • For dates in years 2015 and onward, the year will stay 2014, and the month will be the number it would be if the same month cycle in 2014 were to continue forever past month 12. So 2015-02-08 would be 2014-14-08, and 2020-12-31 would be 2014-85-02. Note that leap days are not accounted for because 2014 is not a leap year.

Your task is to build a program or function that will take a Julian astronomical date as input and return a string with the date corresponding to that Julian date in Eternal 2014 notation, in either YYYY-MM-DD or DD/MM/YYYY format.

You may assume that the Julian day entered will always be an integer from 1721426 (January 1, 1) to 2914695 (January 23, 3268) inclusive. Years may contain leading zeros to pad to 4 digits or not, but months and days must always have leading zeros to pad to two digits (and years may not contain leading zeros to pad to any number of digits other than 4).

Here are some example inputs and their outputs, in all acceptable formats:

> 1721426
1-01-01
01/01/1
0001-01-01
01/01/0001

> 2086302
999-12-31
31/12/999
0999-12-31
31/12/0999

> 2456659
2014-01-01
01/01/2014

> 2456789
2014-05-11
11/05/2014

> 2457024
2014-13-01
01/13/2014

> 2457389
2014-25-01
01/25/2014

> 2469134
2014-411-07
07/411/2014

> 2567890
2014-3657-29
29/3657/2014

> 2914695
2014-15059-23
23/15059/2014

You may not use any built-in date processing libraries in your language. All calculations must be done algorithmically within the program's source code itself.

The shortest program (in bytes) to achieve this in any language wins.

\$\endgroup\$
  • 3
    \$\begingroup\$ Haha, this question gets 25 upvotes right as the Winter Bash begins. \$\endgroup\$ – Joe Z. Dec 14 '15 at 5:01
12
\$\begingroup\$

Python 2, 166 bytes

n=input()
d=m=y=1
M=([3]+[3,2]*3)*2
while n>1721426:
 n-=1;d+=1;M[2]=y%400<1or y%4<1<y%100
 if d>M[m%12]+28:m+=1;d=1
 if m>12<2014>y:y+=1;m=1
print'%02d/'*2%(d,m)+`y`

This cycles through every day from January 1, 1 (1721426) to the given date, incrementing the current day, month and year as it goes. The last test case takes about a second on my computer.

Output is printed in the second format:

01/01/1
31/12/999
23/15059/2014
\$\endgroup\$
3
\$\begingroup\$

Ostrich 0.5.0, 197 bytes

G~:J1401+4J*274227+146097/F3*4/F+38~+:f4*3+:e1461:p%4/F:g5*2+:h153:s%5/F1+:D;hs/F2+12:n%1+:M;ep/F4716-n2+M-n/F+:Y;{2014:Y;D365+:D;{M1-12%[31:x28x 30:yxyxxyxyx]=:dD<.{Dd-:D;M1+:M;}*}(}Y2014-*D"/M"/Y

Ungolfed (ha):

G~:J;
4716:y;1401:j;2:m;12:n;4:r;1461:p;3:v;5:u;153:s;2:w;274277:B;38~:C;
Jj+4J*B+146097/F3*4/F+C+:f;
rf*v+:e;
ep%r/F:g;
ug*w+:h;
hs%u/F1+:D;
hs/Fm+n%1+:M;
ep/Fy-nm+M-n/F+:Y;
{
2014:Y;
D365+:D;
{
M1-12%[31 28 31 30 31 30 31 31 30 31 30 31]=:d
D<.{Dd-:D;M1+:M;}*
}(
}Y2014-*
D"/M"/Y

I'm... really just exhausted from all the New Year's happiness and what not. That's why I haven't golfed this very much. I may or may not come back to make it better later.

Algorithm from https://en.wikipedia.org/wiki/Julian_day#Gregorian_calendar_from_Julian_day_number

\$\endgroup\$
0
\$\begingroup\$

PHP (278)

Run on command line using php -R '<code>'. (The flag counts as one character.)

if(0<$N=($n=$argn-1721426)-735233){$n=$N%365+735233;$o=12*($N/365|0);}for($y=1+400*($n/146097|0)+100*(($n%=146097)/36524|0)+(($n%=36524)/1461<<2)+(($n%=1461)/365|0);($n%=365)>=$d=@++$m-2?30+($m+($m>>3)&1):29-($y%4||!($y%100)&&$y%400);)$n-=$d;printf("$y-%02d-%02d",$m+@$o,$n+1);

More readable version (run using filename and without -R):

<?php

// step 1: read the input and fix up 2014 dates
if (0 < $N = ($n = fgets(STDIN) - 1721426) - 735233) {
    $n = $N % 365 + 735233; // wrap around to 2014-01-01
    $o = 12 * ($N / 365 | 0); // compute month offset
}

for (

// step 2: extract year
$y = 1
    + 400 * ($n / 146097 | 0)
    + 100 * (($n %= 146097) / 36524 | 0)
    + (($n %= 36524) / 1461 << 2)
    + (($n %= 1461) / 365 | 0);

// step 3: extract month and day
($n %= 365) >= $d = @++$m - 2
    ? 30 + ($m + ($m >> 3) & 1)
    : 29 - ($y % 4 || !($y % 100) && $y % 400);

) $n -= $d;

// step 4: print date string, adding the month offset
// previously computed in step 1.
printf("$y-%02d-%02d", $m + @$o, $n + 1);
\$\endgroup\$
0
\$\begingroup\$

C (sort of ... gcc allows it) 183

Lots of warnings for non-standardness and probably incredibly unportable, but it works on my machine today.

y=1;m;d;main(n,a){for(n=atoi(a[1]);n-->1721426;)++d>((m%12<7?m%2==0:m%2!=0)?30:m%12-1?29:y%(y%100?4:400)?27:28)&&(++m,d=0,m>11&&y<2014)&&(++y,m=0);printf("%d-%02d-%02d\n",y,m+1,d+1);}

It uses the same algorithm as the Python 2 answer by @grc

The output after compiling is

test2014 2086302
999-12-31

test2014 2456659
2014-01-01

test2014 2456789
2014-05-11

test2014 2457024
2014-13-01

test2014 2457389
2014-25-01

test2014 2469134
2014-411-07

test2014 2567890
2014-3657-29

test2014 2914695
2014-15059-23
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.