Take the 2-minute tour ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

A date can be represented by an unsigned integer as such: YYYYMMDD. What you need to do, is write the shortest program or function that figures out the most recent date whose number was divisible by a given number n (including today's date) and then returns that date in the format showed above. If there has never been a date (between 00000101 and today inclusive) divisible by the given integer, you should return -1.

Examples

Current Date     Input     Output

30 July, 2014      4       20140728
30 July, 2014      7       20140729
28 July, 2014      4       20140728
28 July, 2014      7       20140722
28 July,    5    90000     -1

Input

You can read from STDIN or take a function argument or even expect the input to be stored in a variable. The input will be an unsigned integer.

Output

Write to STDOUT or return (or save in a variable) the integer representing the date in the format YYYYMMDD.

Restrictions

You may use any standard library your language offers. Standard loopholes apply.

Winning conditions

This is a , so smallest program (in bytes) wins. In case of a tie, the answer with the most votes wins.

share|improve this question
4  
Date 00000101 does not exist. Year count starts by 1. en.wikipedia.org/wiki/0_%28year%29 –  edc65 Jul 30 at 14:35
1  
@edc65 can we pretend it does exist? –  overactor Jul 30 at 14:37
3  
What about Feb 29th? Do we need to apply full leap year rules to check for valid dates? en.wikipedia.org/wiki/Leap_year –  DigitalTrauma Jul 30 at 14:52
5  
What about the days lost due to the Julian-Gregorian calendar switch? Or are we going Gregorian all the way? en.wikipedia.org/wiki/Gregorian_calendar –  DigitalTrauma Jul 30 at 14:56
1  
Your input/output specs are rather loose. For example, should the "expect the input to be stored in a variable" count the variable declaration in a language like C? You say "write a program", yet you say "take a function argument" - does that mean we can write just a function rather than a full program? –  Bob Jul 30 at 16:43

21 Answers 21

up vote 15 down vote accepted

Mathematica, 93 60 bytes

For[i=0,(r=DatePlus@i--~FromDigits~100)>0&&!n∣r,];r~Max~-1

Expects the input to be stored in n.

Note that the vertical line is the unicode character for "divides", which I've counted as 3 bytes (UTF-8).

Edit: Found a neat trick to avoid the bloated DateString and format specification :).

Edit: Totally forgot about the -1 requirement. Fixed now.

Here is an explanation

For[i=0,            i--                        ,];         (* i is the number of days AFTER
                                                              today. Hence, we decrement 
                                                              it. *)
For[i=0,   DatePlus@i--                        ,];         (* If no reference date is
                                                              provided, DatePlus will add
                                                              the given number of days to
                                                              today's date. The result is a 
                                                              list of 3 integers, luckily 
                                                              in order {year,month,day} *)
For[i=0,   DatePlus@i--~FromDigits~100         ,];         (* Interpret these as the digits
                                                              of a base 100 number. The 
                                                              beauty is that FromDigits
                                                              doesn't care about digits 
                                                              greater than the base and 
                                                              just carries them over. *)
For[i=0,(r=DatePlus@i--~FromDigits~100)        ,];         (* Store the number in r. *)
For[i=0,(r=DatePlus@i--~FromDigits~100)>0      ,];         (* Make sure it's positive. *)
For[i=0,(r=DatePlus@i--~FromDigits~100)>0&&!n|r,];         (* And keep going while n does 
                                                              not divide r. *)
For[i=0,(r=DatePlus@i--~FromDigits~100)>0&&!n|r,];r~Max~-1 (* Clamp result to -1. *)

Note that I've used | instead of in the explanation, because the Unicode one messes with monospacing.

share|improve this answer
    
+1.Do you have a link pointing out that you should count unicode chars as 3 bytes? –  belisarius Jul 30 at 18:21
2  
@belisarius The OP stated that this code golf is counted by bytes and not characters (this is also the default as stated in the tag wiki). –  Martin Büttner Jul 30 at 18:24
    
I never got to read thru the end of the wiki :) Thanks! –  belisarius Jul 30 at 18:29

Python 2 - 150

import datetime as d,re
def f(n):
 t=d.date.today()
 while t:
    c=int(re.sub("-","",str(t)))
    if c%n<1:return c
    try:t-=d.timedelta(1)
    except:return-1

Thanks @chill0r for suggestion to remove days=, and Jason S for tip that the try block can be reduced to one line.

share|improve this answer
    
Yes. That is a standard operating procedure ;). The tabs get converted to spaces after pasting. –  bitpwner Jul 30 at 15:06
    
You can remove the days= in t-=d.timedelta(days=1). This works fine too (at least in python3) –  chill0r Jul 30 at 15:20
    
@bitpwner ah I see, never mind then. –  Martin Büttner Jul 30 at 15:27
1  
You can save more: (1) use int(t.strftime("%Y%m%d")) and drop re, (2) use a one-line try because only t-=d.timedelta(1) needs to be in it. –  Jason S Jul 31 at 4:33
1  
@bitpwner strftime on older dates works in python3, checked and I do get an error in python2 –  Jason S Jul 31 at 8:17

C# 136

With the revised specs, a function that takes an unsigned int and returns an int.

int F(uint n){var d=System.DateTime.Now;int i;try{while((i=int.Parse(d.ToString("yyyMMdd")))%n>0)d=d.AddDays(-1);}catch{i=-1;}return i;}

152 characters with variable input/output

Taking advantage of the loose input/output requirements, input is to be stored in the variable n (currently counting all characters except the integer literal), and output is provided with the variable s.

class P{static void Main(){var n=4;var d=System.DateTime.Now;string s;try{while(int.Parse(s=d.ToString("yyyMMdd"))%n>0)d=d.AddDays(-1);}catch{s="-1";}}}

204 characters with STDIN/STDOUT:

using System;class P{static void Main(){int n=int.Parse(Console.ReadLine());var d=DateTime.Now;string s;try{while(int.Parse(s=d.ToString("yyyMMdd"))%n>0)d=d.AddDays(-1);}catch{s="-1";}Console.Write(s);}}
share|improve this answer
1  
Really, a downvote? Does this not solve the problem correctly? Please explain. If anyone thinks I duplicated the other C# answer, I actually wrote this about an hour before the other one, and even looked into using C# 6.0 for the declaration expressions. Got a bit sidetracked, which resulted in posting the answer late. Even then, that's a rather flimsy reason for a downvote. –  Bob Jul 30 at 17:25

T-SQL (2012) - 148

Assumes there is a free variable @n with the n value.

declare @ date=getdate()while convert(char,@,112)%@n>0 and'00010101'<@ set @=dateadd(d,-1,@)print iif(convert(char,@,112)%@n=0,convert(char,@),'-1')
share|improve this answer

Golflua 90 86

n=I.r()d="%Y%m%d"i=O.d(d)+0j=0@i>0?i%n==0w(i)O.q()$j=j+1i=O.d(d,O.t()-j*86400)+0$w(-1)

An ungolfed Lua version would be,

n = io.read()
d = "%Y%m%d"
i = os.date(d)+0   -- implicitly casts os.date(d) to int
j = 0
while i>0 do
   if i % n == 0 then
      print(i)
      os.exit()
   end
   j = j+1
   i = os.date(d,os.time()-j*86400)+0
end
print(-1)
share|improve this answer
2  
Tested here n = 20140699 outputs 20140699 –  William Barbosa Jul 30 at 14:50
    
@WilliamBarbosa: Fixed; 20140699 returns -1. –  Kyle Kanos Jul 30 at 17:36

MATLAB: 61

-1,s=str2num(datestr(1:now,'YYYYmmDD')),d=s(~mod(s,n)),d(end)

Assumes the divisor is stored in n. The result will be stored in a variable called ans.


Commented version:

-1                                     % Store -1 in ans in case we don't find anything
s=str2num(datestr(1:now,'YYYYmmDD'))   % Make a list of date numbers
d=s(~mod(s,n)),                        % Select only those who are dividable and prepend -1
d(end)                                 % Store last found value in ans, if anything is found

Will generate an error if no result is found, but the answer is still available in the variable despite that.


Error could be avoided at the cost of 2 extra chars:

s=str2num(datestr(1:now,'YYYYmmDD')),d=[-1;s(~mod(s,n))],d(end)
share|improve this answer
    
@MartinBüttner Hmm, solved that problem but now the solution is only tied for minimum chars. Can you see any improvements? –  Dennis Jaheruddin Jul 31 at 11:54
1  
No, not off the top of my head. But my motivation to help you beat me is a bit limited. ;) –  Martin Büttner Jul 31 at 12:11

PHP (92=85+7)

Expects input to be stored in $n.

for($d=date("Ymd");!($d%$n==0&checkdate($d/100%100,$d%100,substr($d,0,4))|$d<0);$d--);echo$d

I just remembered why I do not like PHP anymore=)

EDIT: Now the -1 of the specifications is implemented too.

share|improve this answer
    
No, just checked it, $d will be one too low when echo-ing. What do you mean by 'you've forge'? (Sorry, no english native=) –  flawr Jul 30 at 16:05
    
Oh, I didn't see that spec, of course this has to be added, thanks! –  flawr Jul 31 at 12:31

JavaScript (ES6) 115

Expects number in variable n, result stored in variable r. Each day is checked, starting with current date and decrementing - there must be a better way.
Moreover, using standard javascript date functions, all dates are gregorian down to year 1 (with leap years accordingly wrong before gregorian reform).

for(z=new Date,t=n+1;t>n&&t%n;)
  d=z.getDate(),
  t=z.getFullYear()*1e4+(z.getMonth()+1)*100+d,
  z.setDate(d-1);
r=t>n?t:-1
share|improve this answer

C# - 144 (Or 124 in LINQPad) + 1 for each digit in n

This expects the input to be in the variable n. By the end of the execution the desired value will be in the variable r. This considers 00010101 as the first date, though, because the date 00000101 does not exist. Suggestions for improvement are always welcome.

class P{static void Main(){int n=7,r;var d=System.DateTime.Now;try{for(;(r=int.Parse(d.ToString("yyyMMdd")))%n>0;d=d.AddDays(-1));}catch{r=-1;}}}

LINQPad version:

int n=7,r;var d=System.DateTime.Now;try{for(;(r=int.Parse(d.ToString("yyyMMdd")))%n>0;d=d.AddDays(-1));}catch{r=-1;}r.Dump();
share|improve this answer

Groovy - 301 300 chars

Very simple (and slow), with no tricks to hide the fact that it uses Joda Time.

Golfed:

@Grab(group='joda-time', module='joda-time', version='2.3')
import org.joda.time.*
import org.joda.time.format.*
f={DateTimeFormat.forPattern("yyyyMMdd").print(new LocalDate().minusDays(it)) as int}
n=args[0] as int;b=0;x=-1;c=0
while(!b){if(f(c++)%n==0){x=f(--c);b=1};if(f(0)-c<=101){b=1}}
println x

Example run (on 7/30/2014):

$ groovy D.groovy  7
20140729
$ groovy D.groovy  16
20140720
$ groovy D.groovy  90000
-1

Ungolfed:

@Grab(group='joda-time', module='joda-time', version='2.3')

import org.joda.time.*
import org.joda.time.format.*

f = { DateTimeFormat.forPattern("yyyyMMdd").print(new LocalDate().minusDays(it)) as int }

n = args[0] as int
b = 0 
x = -1
c = 0

while (!b) {
    if(f(c++)%n==0) { x=f(--c); b=1}
    if(f(0)-c<=101){b=1}
}

println x
share|improve this answer

R, 146 139

D=function(n){
z=as.double(gsub("-","",y<-Sys.Date()))
d=F
while(z>100&!d){
y=y-1 
z=as.double(gsub("-","",y))
d=!z%%n}
ifelse(z>100,z,-1)}

Good luck with a date that doesn't work. microbenchmark reports it takes about half a second to go back 15 days. As of July 31, 2014, this will take something like 20 million seconds (~23 days) to spit out -1, at least according to the back of the envelope.

edit: some shortcuts in the comments

share|improve this answer
    
!d is shorter than d==F and !z%%n than z%%n==0. Also, making as.numeric(gsub("-","",...) into a function should reduce the character count as well. Still, nice job! –  plannapus Jul 31 at 11:26
    
Oh and as.real is often a good, shorter alternative to as.numeric. –  plannapus Jul 31 at 11:32
    
Unfortunately as.real is defunct as of R 3.0.0. But we still have as.double which is one character shorter. –  ssdecontrol Jul 31 at 12:25
    
Oh I didn't know that as I'm still using R 2.14 –  plannapus Jul 31 at 12:26
1  
I'm not working on a computer i have administration rights on, so it's not really up to me. But I already have paste0 in my .Rprofile naturally :) –  plannapus Jul 31 at 12:33

Matlab 104

function d=f(v);for d=fix(now):-1:1 d=str2num(datestr(d,'YYYYmmDD'));if~mod(d,v)return;end;end;d=-1;end

Ungolfed :

function d = f(v)
   for d=fix(now):-1:1
       d = str2num(datestr(d,'YYYYmmDD'));
       if ~mod(d,v)
          return; 
       end
   end
   d = -1;
end

EDIT: I managed to optimise it a bit, but @DennisJaheruddin has the real solution here

share|improve this answer
    
This can still be golfed quite a bit, I will update it. –  Dennis Jaheruddin Jul 31 at 10:28
    
@DennisJaheruddin I have rejected your edit based on this meta post. Please suggest your improvements in a comment, so the OP can review them before modifying his answer. –  Martin Büttner Jul 31 at 10:40
    
Note that you can save chars in various ways: Use a script rather than a function, let things get assigned to ans, do the loop from low to high and let each result overwrite the previous one so you don't need to break the loop. -- Of course vectorization can also help, see my answer. –  Dennis Jaheruddin Jul 31 at 12:11
    
Here is a shorter loop based version of 67 chars: -1,for s=str2num(datestr(1:now,'YYYYmmDD'))',if~mod(s,n),+s,end,end –  Dennis Jaheruddin Jul 31 at 12:47
    
@MartinBüttner Thanks for the comment. There was an error as you said. Now it should be okay. –  Scott Jul 31 at 12:53

Python 3 - 151 148 bytes, generators

from datetime import*
t=date.today()
f=lambda n:next((y for y in(int((t-timedelta(o)).strftime("%Y%m%d"))for o in range(t.toordinal()))if y%n<1),-1)

Thanks @nyuszika7h for import* suggestion

share|improve this answer

Ruby 103

require'date'
f=->{d=Date.today 
(s=d.strftime('%Y%m%d').to_i
return s if s%n<1
d-=1)while d.year>0
-1}

Input

Expects the divisor value to be present in variable n.

Output

The return value of the f function

Online example: http://ideone.com/LoYxG4

share|improve this answer

Java : 373 chars

This is a port of the Groovy answer, and uses Joda Time.

Golfed:

import org.joda.time.*;
import org.joda.time.format.*;
public class D {
static int f(int i){return Integer.parseInt(DateTimeFormat.forPattern("yyyyMMdd").print(new LocalDate().minusDays(i)));}
public static void main(String[] args){
int n=Integer.parseInt(args[0]);int b=0,c=0,x=-1;
while(b!=1){if(f(c++)%n==0){x=f(--c);b=1;};if(f(0)-c<=101){b=1;}}
System.out.println(x);}}

Sample runs (with joda-time-2.4.jar on classpath:

$ java D 7
20140729
$ java D 4
20140728
$ java D 16
20140720
$ java D 90000
-1

Ungolfed:

import org.joda.time.*;
import org.joda.time.format.*;

public class D {
    static int f(int i) {
        return Integer.parseInt(DateTimeFormat.forPattern("yyyyMMdd").print(new LocalDate().minusDays(i)));
    }

    public static void main(String[] args) {
        int n = Integer.parseInt(args[0]);
        int b = 0,c = 0,x = -1;

        while(b!=1) {
            if(f(c++)%n==0) { x=f(--c);b=1; }
            if(f(0)-c<=101) { b=1; }
        }

        System.out.println(x);
    }
}
share|improve this answer
3  
There's also java.time.* in the latest version of Java. –  ntoskrnl Jul 31 at 10:26

Bash+coreutils (8.21), 67 bytes

seq -f-%gday $[9**9]|date -f- +[pq]sp[_1pq]sq%Y%m%ddA1=qd$1%%0=p|dc
  • seq generates integers from 1 to 99, one per line, and formats it as -<x>day
  • pipe this to date -f which interprets each line and outputs the date formatted into a dc expression such as [pq] sp [_1pq] sq 20140728 d A1 =q d 7% 0=p (spaces added for readability)
    • [pq] define a macro to print the top of stack, then quit
    • sp save macro in register p
    • [pq] define a macro to push -1, print the top of stack, then quit
    • sq save macro in register q
    • 20140728 embedded date integer
    • d duplicate top of stack
    • A1 push 101 (00000101)
    • =q pop top 2 stack values: compare date and 101, and call macro q if equal
    • 7 push divider
    • % pop divider and dividee, the divide and push the remainder
    • 0 push 0
    • =p pop top 2 stack values: compare remainder and 0, and call macro p if equal
    • d duplicate top of stack
    • macro p is called: prints date integer and quits dc entirely
  • dc expressions are piped to dc for evaluation. Once dc prints the right value and quits, the rest of the pipeline is torn down

Output:

$ ./lastdivdate.sh 4
20140728
$ ./lastdivdate.sh 7
20140729
$ ./lastdivdate.sh 123456
17901120
$ ./lastdivdate.sh 77777
19910912
$ ./lastdivdate.sh 7777777
-1
$ 

Since this program generates integers from 1 to 99, it will be valid up to just over 1 million years into the future. I hope this limitation is acceptable ;-)


Thanks @WumpusQ.Wumbley for shortening the return of -1.

share|improve this answer
    
@MartinBüttner Curses! Now it does, with a 19 byte penalty :) –  DigitalTrauma Jul 31 at 0:51
    
Shorter ways to convert empty output to -1: add |grep .||echo -1 to the end of the pipeline, or use zsh where you can nest expansions like echo ${$(cmd):-1} (this will cost you a backslash elsewhere...) –  Wumpus Q. Wumbley Jul 31 at 13:01
    
@WumpusQ.Wumbley Why didn't I think of that? Thanks! –  DigitalTrauma Jul 31 at 16:52
1  
By the way, this seems to be sensitive to the coreutils version. Mine (8.15) refuses to go back before 1901 with the "days ago" specification. –  Wumpus Q. Wumbley Jul 31 at 17:02
1  
Actually it seems to be a sizeof time_t issue, since the boundary where it breaks is 2**31 seconds before 1/1/1970. My older installation is also pathetically 32-bit –  Wumpus Q. Wumbley Jul 31 at 17:25

PYTHON: 134 bytes

Not going to be able to beat the current leader, and it's not that much better than the best Python answer, but I decided to post my best Python solution.

from datetime import*
def y(a,n):
 s=a.strftime("%Y%m%d")
 if int(s)%n==0:yield s
 try:x=y(a-timedelta(1),n)
 except:yield -1
 yield x

Ungolfed:

from datetime import *
def y(a, n):
    s=int(a.strftime("%Y%m%d"))
    if s%n==0:
        yield s
    try:
        x=y(a-timedelta(1), n)
    except:
        yield -1
    yield x
share|improve this answer
    
It's actually 138 bytes. You can save 4 bytes by using from datetime import* instead of import datetime as d, timedelta(1) instead of d.timedelta(1) and yield instead of return. –  nyuszika7h Aug 1 at 13:31
    
I'm using a random online byte counter, is there a better option? –  Batman Aug 1 at 13:34
    
mothereff.in/byte-counter –  nyuszika7h Aug 1 at 13:36
    
What makes that one different from this one? bytecount.bluebus112.com –  Batman Aug 1 at 13:40
    
That one doesn't count newlines, plus it counts characters, not bytes. For ASCII text, the two are the same, so the latter doesn't make a difference here. In code-golf, you usually count characters unless the OP says otherwise. (Also, the one I linked was the first result in Google for "byte count" here.) –  nyuszika7h Aug 1 at 13:41

JavaScript (ES5) - 94

It expects the input in variable x, and places the output in o.

for(i=Date.now();i>-7e13&&(o=(new Date(i)).toISOString().replace(/-|T.*/g,''))%x;i-=864e5)o=-1
share|improve this answer

k4 (84) (73)

f:{f d@*|&~.q.mod[(f:{$[^x;-1;.($x)@&~"."=$x]})'d:{"d"$x+!1+"i"$y-x}[-730457;.z.D];x]}

This is just an initial cut with the first algorithm that came to mind; I'm sure better is possible in both performance and length.

This version hardcodes the "today" part (that's the .z.D); change it to a date literal (yyyy.mm.dd) or an integer in the q date system (days since January 1, 2000) to run the test cases. (q won't parse date literals earlier than the early eighteenth century, so for dates before that, you'll need to work out the value and use the appropriate integer directly. January 1, "A.D. 0", from the spec, turns out to be -730457, which is used in the function code. July 28, A.D. 5, from the last test case, turns out to be -728450.)

The given test cases:

  {f d@*|&~.q.mod[(f:{$[^x;-1;.($x)@&~"."=$x]})'d:{"d"$x+!1+"i"$y-x}[-730457;2014.07.30];x]}4
20140728
  {f d@*|&~.q.mod[(f:{$[^x;-1;.($x)@&~"."=$x]})'d:{"d"$x+!1+"i"$y-x}[-730457;2014.07.30];x]}7
20140729
  {f d@*|&~.q.mod[(f:{$[^x;-1;.($x)@&~"."=$x]})'d:{"d"$x+!1+"i"$y-x}[-730457;2014.07.28];x]}4
20140728
  {f d@*|&~.q.mod[(f:{$[^x;-1;.($x)@&~"."=$x]})'d:{"d"$x+!1+"i"$y-x}[-730457;2014.07.28];x]}7
20140722
  "d"$-728450
0005.07.28
  {f d@*|&~.q.mod[(f:{$[^x;-1;.($x)@&~"."=$x]})'d:{"d"$x+!1+"i"$y-x}[-730457;-728450];x]}90000
-1

edit:

g:.,/$`\:`$$:;f:{$[Z=r:{(z>x)&.q.mod[g z]y}[Z:-730458;y]{x-1}/x;-1;g"d"$r]}

This is a different approach which uses one of the convergence operators to decrement the date until either it finds a divisible one or it crosses the 1/1/0000 boundary. It also does the conversion from date to integer slightly differently.

The test cases, this time all at once:

  g:.,/$`\:`$$:;{$[Z=r:{(z>x)&.q.mod[g z]y}[Z:-730458;y]{x-1}/x;-1;g"d"$r]}'[2014.07.30 2014.07.30 2014.07.28 2014.07.28,"d"$-728450;4 7 4 7 90000]
20140728 20140729 20140728 20140722 -1
share|improve this answer

VBA 343 bytes (module)

Sub divD(i As Long)
a = Now()
b = Format(a, "yyyymmdd")
    Do While b / i <> Int(b / i)
    a = DateAdd("d", -1, a)
    b = Format(a, "yyyymmdd")
        If b = "01000101" Then
            MsgBox -1
            Exit Sub
        End If
    Loop
MsgBox b
End Sub
share|improve this answer

PowerShell - 76

This depends on the number being stored in the variable $n.

try{@(0..$n|%{'{0:yyyyMMdd}'-f(date).AddDays(-$_)}|?{!($_%$n)})[0]}catch{-1}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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