Date Multiplying Challenge

19

1

(Inspired by last week's Riddler on FiveThirtyEight.com. Sandbox post.)

Given a year between 2001 and 2099, calculate and return the number of days during that calendar year where mm * dd = yy (where yy is the 2-digit year).

2018, for example, has 5:

  • January 18th (1 * 18 = 18)
  • February 9th (2 * 9 = 18)
  • March 6th (3 * 6 = 18)
  • June 3rd (6 * 3 = 18)
  • September 2nd (9 * 2 = 18)

Input can be a 2 or 4-digit numeric year.

Output should be an integer. Optional trailing space or return is fine.

Complete input/output list:

Input = Output
 2001 = 1     2021 = 3     2041 = 0     2061 = 0     2081 = 2
 2002 = 2     2022 = 3     2042 = 4     2062 = 0     2082 = 0
 2003 = 2     2023 = 1     2043 = 0     2063 = 3     2083 = 0
 2004 = 3     2024 = 7     2044 = 3     2064 = 2     2084 = 5
 2005 = 2     2025 = 2     2045 = 3     2065 = 1     2085 = 1
 2006 = 4     2026 = 2     2046 = 1     2066 = 3     2086 = 0
 2007 = 2     2027 = 3     2047 = 0     2067 = 0     2087 = 1
 2008 = 4     2028 = 4     2048 = 6     2068 = 1     2088 = 3
 2009 = 3     2029 = 1     2049 = 1     2069 = 1     2089 = 0
 2010 = 4     2030 = 6     2050 = 3     2070 = 3     2090 = 5
 2011 = 2     2031 = 1     2051 = 1     2071 = 0     2091 = 1
 2012 = 6     2032 = 3     2052 = 2     2072 = 6     2092 = 1
 2013 = 1     2033 = 2     2053 = 0     2073 = 0     2093 = 1
 2014 = 3     2034 = 1     2054 = 4     2074 = 0     2094 = 0
 2015 = 3     2035 = 2     2055 = 2     2075 = 2     2095 = 1
 2016 = 4     2036 = 6     2056 = 4     2076 = 1     2096 = 4
 2017 = 1     2037 = 0     2057 = 1     2077 = 2     2097 = 0
 2018 = 5     2038 = 1     2058 = 0     2078 = 2     2098 = 1
 2019 = 1     2039 = 1     2059 = 0     2079 = 0     2099 = 2
 2020 = 5     2040 = 5     2060 = 6     2080 = 4

This is a challenge, lowest byte count in each language wins.

Pre-calculating and simply looking up the answers is normally excluded per our loophole rules, but I'm explicitly allowing it for this challenge. It allows for some interesting alternate strategies, although its not likely a 98 99-item lookup list is going to be shortest.

BradC

Posted 2018-04-13T14:31:39.840

Reputation: 6 099

If it makes it any easier in your language, the answer will be the same regardless of century; 1924 and 2124 have the same number of days as 2024. – BradC – 2018-04-13T14:41:13.813

if the the result of mm*dd is bigger than 100 it is automatically filtered? – DanielIndie – 2018-04-13T16:03:21.503

@DanielIndie Correct, no "wraparound" dates should be counted. In other words, Dec 12, 2044 doesn't count, even though 12 * 12 = 144. – BradC – 2018-04-13T16:13:10.110

As we need only handle a limited number of inputs, I've edited them all in. Feel free to rollback or reformat. – Shaggy – 2018-04-13T17:20:49.320

I believe 2078 should be 2 and 2087 should be 1 – Asone Tuhid – 2018-04-13T17:58:03.300

@Arnauld Oops, off-by-one error. Same reason I submitted the wrong answer on the original 538.com puzzler. – BradC – 2018-04-13T18:01:21.453

That's fine, @Shaggy, I fixed the errors mentioned by Asone (which I also verified). – BradC – 2018-04-13T18:06:26.130

Does Input can be a 2 or 4-digit numeric year mean that the submitter can decide or that the program needs to accept both as valid? – 640KB – 2019-02-04T18:57:22.670

1@gwaugh Just that you can decide which to accept as valid input (so you don't have to spend extra characters converting between the two). – BradC – 2019-02-04T20:06:54.097

Answers

14

Excel, 48 bytes

Hooray! Finally something Excel is actually good at.

=COUNT(VALUE(ROW(1:12)&"/"&A1/ROW(1:12)&"/"&A1))

Takes input from A1 in the form of an integer 1-99 representing the year, and outputs to wherever you enter this formula. It's an array formula, so use Ctrl-Shift-Enter instead of Enter to enter it.

This takes advantage of the fact that COUNT ignores errors, so any errors that are caused by either the month not dividing the year (leading Excel to parse something like 2/12.5/25 or by the date not being valid, like 2/29/58, are just silently ignored.

Sophia Lechner

Posted 2018-04-13T14:31:39.840

Reputation: 1 200

1Very nice. Probably worth mentioning it requires a 2-digit year in A1. Entering a 4-digit year simply returns 0. – BradC – 2018-04-13T19:14:59.747

True! I'll edit that into the description. – Sophia Lechner – 2018-04-13T19:16:18.943

Also I should mention that it's locale-specific; it depends on having a locale that uses a mm/dd/yy ordering. In a locale with dd/mm/yy ordering, the answer would be the same number of bytes, of course. – Sophia Lechner – 2018-04-13T19:20:28.347

1Super clever; I like how you're only testing 12 date candidates (one per month), instead of running through every day of the year. – BradC – 2018-04-13T19:26:20.853

Fix the year to a non-leap one save byte? – l4m2 – 2018-05-04T02:59:58.250

6

Python 2, 44 bytes

[k/32%13*(k%32)for k in range(96,509)].count

Try it online!

An anonymous function given as a method object. Produces all products of (month, day) pairs (m, d) as encoded by k=32*m+d with 0≤m≤12, 0≤d≤31, wrapping around. Eliminates Feb 29-31 by excluding them from the range.

xnor

Posted 2018-04-13T14:31:39.840

Reputation: 115 687

5

Java (JDK 10), 65 bytes

y->{int m=13,c=0;for(;m-->1;)if(y%m<1&y/m<29+m%2*3)c++;return c;}

Try it online!

Credits

Olivier Grégoire

Posted 2018-04-13T14:31:39.840

Reputation: 10 647

No leap year fits 29*n, so no need the check – l4m2 – 2018-04-13T16:36:01.673

Thanks for your input. I could remove 27 bytes in total with a bunch of other changes. – Olivier Grégoire – 2018-04-13T18:07:58.907

1

Changing (m==2?29:32) to 29+m%2*3 still seems to give all OK results. Credit to @AsoneTuhid's Ruby answer.

– Kevin Cruijssen – 2018-04-16T06:52:20.353

4

PowerShell, 94 bytes

param($a)for($x=Date 1/1/$a;$x-le(Date 12/9/$a);$x=$x.AddDays(1)){$z+=$x.Month*$x.Day-eq$a};$z

Try it online!

Takes input as a two-digit year, then constructs a for loop from 1/1/year to 12/9/year (because 12/10 and beyond will never count and this saves a byte). Each iteration, we increment $z iff the .Month times the .Day is equal to our input year. Outside the loop, $z is left on the pipeline and output is implicit.

Edit - this is culture dependent. The above code works for en-us. The date format may need to change for other cultures.

AdmBorkBork

Posted 2018-04-13T14:31:39.840

Reputation: 41 581

2"culture"? Did you mean "locale"? ... – user202729 – 2018-04-13T15:31:35.453

1

@user202729 Colloquially, yes, but PowerShell documentation refers to it as "culture."

– AdmBorkBork – 2018-04-13T15:33:17.260

"Culture" is the word MS generally uses to talk about locale, eg. System.Globalization.CultureInfo in .NET.

– sundar - Reinstate Monica – 2018-06-29T18:31:01.877

4

JavaScript (Node.js), 48 44 43 bytes

F=(x,h)=>h>12?0:F(x,-~h)+(x/h<3*h%6+28>x%h)

Try it online!

JavaScript (Node.js), 59 58 bytes

x=>[a=0,...'030101001010'].map((k,m)=>x%m|x/m>31-k||a++)|a

Try it online!

l4m2

Posted 2018-04-13T14:31:39.840

Reputation: 5 985

I knew a mathematical solution would be short, but I had fun with my version :) – Shaggy – 2018-04-13T16:48:14.073

4

Ruby, 46 42 bytes

->y{(1..12).count{|j|y%j<1&&y/j<29+j%2*3}}

Try it online!

Asone Tuhid

Posted 2018-04-13T14:31:39.840

Reputation: 1 944

3

JavaScript, 91 85 82 81 77 bytes

Takes input as a 2-digit string (or a 1 or 2 digit integer).

Takes advantage of the fact that new Date will rollover to the next month, and continue doing so, if you pass it a day value that exceeds the number of days in the month you pass to it so, on the first iteration, it tries to construct the date yyyy-01-345 which becomes yyyy-12-11, or yyyy-12-10 on leap years. We don't need to check dates after that as 12*11+ results in a 3-digit number.

y=>(g=d=>d&&([,M,D]=new Date(y,0,d).toJSON().split(/\D/),D*M==y)+g(--d))(345)

3 bytes saved thanks to Arnauld.


Test It

f=
y=>(g=d=>d&&([,M,D]=new Date(y,0,d).toJSON().split(/\D/),D*M==y)+g(--d))(345)
o.innerText=[...Array(99)].map((_,x)=>(2001+x++)+` = `+f(x)).join`\n`
pre{column-count:5;width:480px;}
<pre id=o></pre>

Shaggy

Posted 2018-04-13T14:31:39.840

Reputation: 24 623

3

Jelly, 15 bytes

31x12_2¦3RĖP€Fċ

Try it online!

Take a number in range [0,100[ as input.

user202729

Posted 2018-04-13T14:31:39.840

Reputation: 14 620

3

JavaScript (ES6), 91 bytes

I was curious to know how hardcoding would compare to an iterative computation. It's definitely longer (see @Shaggy's answer), but not awfully longer.

Edit: It is, however, much longer than a more direct formula (see @l4m2 answer).

Takes input as an integer in [1..99].

n=>(k=parseInt('8ijkskercdtbnqcejh6954r1eb2kc06oa3936gh2k0d83d984h'[n>>1],36),n&1?k>>3:k&7)

Try it online!

How?

Odd years have significantly less chance of having mm * dd = yy than even years. More concretely, odd years have 0 to 3 matches, while even years have 0 to 7 matches. This allows us to code each pair of years with just 5 bits, which can conveniently be represented as a single character in base 36.

Arnauld

Posted 2018-04-13T14:31:39.840

Reputation: 111 334

3

Bash + GNU utilities, 57

  • 1 byte saved thanks to @SophiaLechner
seq -f1/1/$1+%gday 0 365|date -f- +%m*%d-%y|bc|grep -c ^0

Note that the seq command always produces a list of 366 dates - for non-leap years January 1st of the next year will be included. However in the date range 2001..2099, MM*DD will never be YY for January 1st of the next year for any of these years, so this extra day won't affect the result.

Try it online!

Digital Trauma

Posted 2018-04-13T14:31:39.840

Reputation: 64 644

Very nice - I hadn't even known date will do date math like that while parsing. seq doesn't need a space after the -f, so you can save a byte there. – Sophia Lechner – 2018-04-16T17:22:12.930

3

Python 2 and 3, 55 52 bytes

lambda y:sum(y%i<(y/i<29+i%2*3)for i in range(1,13))

Try it online!

Asone Tuhid

Posted 2018-04-13T14:31:39.840

Reputation: 1 944

3

Perl 6, 40 bytes

{+grep {$_%%$^m&&29+$m%2*3>$_/$m},1..12}

Try it online!

nwellnhof

Posted 2018-04-13T14:31:39.840

Reputation: 10 037

3

T-SQL, 123 121 bytes

Per our IO rules, input is taken via pre-existing table t with an integer field y, which contains a 2-digit year.

WITH c AS(SELECT 1m UNION ALL SELECT m+1FROM c WHERE m<12)
SELECT SUM(ISDATE(CONCAT(m,'/',y/m,'/',y)))FROM c,t WHERE y%m=0

Line break is for readability only. Inspired largely by Sophia's Excel solution.

  • The top line generates a 12-item number table c which is joined to the input table t.
  • If that passes I mash together a date candidate using CONCAT(), which does implicit varchar datatype conversions. Otherwise I'd have to do a bunch of CAST or CONVERT statements.
  • Found the perfect evaluation function ISDATE(), which returns 1 for valid dates and 0 for invalid dates.
  • Wrap it in a SUM and I'm done.
  • EDIT: Moved the integer division check (y%m=0) into the WHERE clause to save 2 bytes, thanks @RazvanSocol.

Unfortunately, it's not much shorter than the lookup table version (using the string from osdavison's version):

T-SQL lookup, 129 bytes

SELECT SUBSTRING('122324243426133415153317223416132126011504033106131204241006003213011306002122042005101305111014012',y,1)FROM t

EDIT: Leaving my original above, but we can save a few bytes by using a couple of new functions:

  • STRING_SPLIT is available in MS SQL 2016 and above.
  • CONCAT_WS is available in MS SQL 2017 and above.
  • As above, replaced IIF with WHERE

MS-SQL 2017, 121 118 bytes

SELECT SUM(ISDATE(CONCAT_WS('/',value,y/value,y)))
FROM t,STRING_SPLIT('1-2-3-4-5-6-7-8-9-10-11-12','-')
WHERE y%value=0

MS-SQL 2017, extra cheaty edition: 109 bytes

SELECT SUM(ISDATE(CONCAT_WS('/',number,y/number,y)))
FROM t,spt_values WHERE number>0AND y%number=0AND'P'=TYPE

Requires you to be in the master database, which contains a system table spt_values that (when filtered by TYPE='P'), gives you counting numbers from 0 to 2048.

BradC

Posted 2018-04-13T14:31:39.840

Reputation: 6 099

Similar to other answers, the order I assemble the date (m/d/y) depends on the locality settings of the SQL instance. Other localities might require a different order, or a different separator, but I don't think would impact the code length. – BradC – 2018-04-13T21:47:30.533

I guess you realized that converting '2/29/64' to a date gives 1964-02-29 (not 2064-02-29), but considering that the years 2000 and 2100 are excluded, it's a nice way to get a shorter code. – Razvan Socol – 2018-04-15T09:45:29.460

Using SPLIT_STRING instead of a CTE brings it down to 120 bytes. Using CONCAT_WS instead of CONCAT saves another character, getting it to 119 bytes. – Razvan Socol – 2018-04-15T09:51:30.203

@RazvanSocol Yeah, I'm not sure where the break is between 2-digit dates that map to 19xx vs 20xx, but both give the same answer. I'll give the other two suggestions a try, thanks! – BradC – 2018-04-15T18:08:43.353

@RazvanSocol See my edit, best I could get from those functions was 121, how did you get 119? The length of value is really holding us back. – BradC – 2018-04-17T14:37:29.970

1Replace IIF with WHERE. – Razvan Socol – 2018-04-17T19:24:59.107

@RazvanSocol Thanks, that worked. I can save even more by using spt_values, but that's kinda cheaty. – BradC – 2018-04-17T20:19:46.657

3

Julia 0.6, 49 44 42 bytes

y->sum(y/i∈1:28+3(i%2⊻i÷8)for i=1:12)

Try it online!

-5 bytes inspired by Asone Tuhid's Ruby answer.
-2 bytes replacing count with sum

Explanation:

For each month i from 1 to 12, calculate y/i, and check if it's one of that month's days. Months with 31 days are 1, 3, 5, 7, 8, 10, 12 - so they're odd below 8 and even at and above 8. So either i%2 or i÷8 (which is 0 for i<8 and 1 for i>=8 here) should be 1, but not both - so we XOR them. If the xor result is true, we check dates 1:28+3 i.e. 1:31, otherwise we check just dates 1:28.

1:28 is sufficient for the rest of the months (this improvement inspired by Asone Tuhid's Ruby answer) because:

  • for February, the only possibility would have been 2*29 = 58, but 2058 is not a leap year, so we can assume Feb always has 28 days.

  • the other months with 30 days are month 4 and above - for which i*29 (and i*30) would be above 100, which can be ignored.

Finally, we count out the number of times y/i belongs in this list of days (by using boolean sum here), and return that.

sundar - Reinstate Monica

Posted 2018-04-13T14:31:39.840

Reputation: 5 296

2

Python 2, 89 84 68 58 bytes

f=lambda y,d=62:d-59and((d/31+1)*(d%31+1)==y)+f(y,-~d%372)

Try it online!

ovs

Posted 2018-04-13T14:31:39.840

Reputation: 21 408

2

Excel, 83 bytes

{=SUM(IF(MONTH(DATE(A1,1,0)+ROW(1:366))*DAY(DATE(A1,1,0)+ROW(1:366))=A1-2000,1,0))}

Input is in cell A1 in the format yyyy. This is an array formula and is entered with Ctrl+Shift+Enter to get the curly brackets {}. It is fairly straightforward and without any cleverness.

When in an array formula, DATE(A1,1,0)+ROW(1:366) gives us an array of 366 date values. On non-leap years, this will include Jan 1 of the next year but that is not a problem because 1*1=1 and would only count as a false positive if the next year is 2001 but, since the required year range is 2001 - 2099, it will never arise as an issue.

If you shorted that bit into simply ~, the formula because much easier to follow:

{=SUM(IF(MONTH(~)*DAY(~)=A1-2000,1,0))}

I tried using COUNTIF() instead of SUM(IF()) but Excel wouldn't even let me enter it as an array formula, much less give me a result. I did find a Google Sheets solution using CountIf() but the same method otherwise that turned out to be 91 bytes, mostly because it uses ArrayFormula() instead of simply { }.

=CountIf(ArrayFormula(Month(Date(A1,1,0)+Row(1:366))*Day(Date(A1,1,0)+Row(1:366))),A1-2000)

Engineer Toast

Posted 2018-04-13T14:31:39.840

Reputation: 5 769

I haven't seen a consensus, but I've generally not been including the outer curly brackets in my byte counts for Excel. They feel more like a way that Excel is formatting its display than part of the formula. Opinions? – Sophia Lechner – 2018-04-13T19:15:12.480

@SophiaLechner I've included them instead of deciding how to include the extra keystrokes required to enter it as an array formula. There's a meta question about that and the only answer says that the CTRL+ALT+ENTER command would count as 1 keystroke. If you use the same as vim (per meta), then that keystroke would count as 1 byte. However, I don't usually count the ENTER at the end of entering a formula as 1 byte in other answers.

– Engineer Toast – 2018-04-13T21:20:47.730

2

Python 3, 158 162 215 241 bytes

Removed 4 Thanks to Stephen for golfing the conditionals.

Removed 53 thanks Stephen for pointing out the white space

Removed 26 thanks to the link provided by caird

I'm pretty new at this. Couldn't think of how to do this without having the days in a month be described.

r=range
def n(Y):
 a,b,c=31,30,0
 for x in r(12):
  for y in r([a,(28if Y%4else 29),a,b,a,b,a,a,b,a,b,a][x]):
   if(x+1)*(y+1)==int(str(Y)[2:]):c+=1
 return c

Try it online!

akozi

Posted 2018-04-13T14:31:39.840

Reputation: 551

5

Welcome to the site, and nice first post! There are a fair few ways you can golf this, such as removing some whitespace, so be sure to check out these tips for golfing in Python

– caird coinheringaahing – 2018-04-13T18:03:08.700

@cairdcoinheringaahing Thanks for the advice the link was very useful! – akozi – 2018-04-13T21:16:38.110

1158 bytes - golfed some away, but mostly you had a big long line of spaces on your third line, dunno how those got there – Stephen – 2019-02-03T18:08:31.273

@Stephen Thanks :) I added yours as two edits. One for the white space and the other as the golfing. – akozi – 2019-02-03T18:17:54.640

(28if Y%4else 29) can be shortened to [29,28][Y%4>0]. Also, the long list can be shortened to [a,...]+2*[a,b,a,b,a]. a,b,c can be added in the parameter list to save a line. int(str(Y)[2:]) can be shortened to Y%100. Finally, counter variables can mostly be shortened to lens of list comprehensions, this also allows n to be made a lambda. This makes 118. – Black Owl Kai – 2019-02-04T00:19:34.697

2

Forth (gforth), 60 59 bytes

: f 0 13 1 do over i /mod swap 32 i 2 = 3 * + 0 d< - loop ;

Try it online!

This version takes advantage of the fact that there can't be more than 1 matching day per month, and that the year has to be divisible by the month for it to match.

Explanation

Iterates over the months, checks if year is divisible by month, and if the quotient is < 31 (28 for Feb) Months after March can't match for days greater than 25, so we can just assume all months (other than Feb) have 31 days for the purpose of the puzzle.

Code Explanation

: f                   \ start new word definition
  0                   \ set up counter
  13 1 do             \ start a counted loop from 1 to 12
    over i /mod       \ get the quotient and remainder of dividing year by month
    swap              \ default order is remainder-quotient, but we want to swap them
    32 i 2= 3 * +     \ we want to compare to 32 days unless month is Feb
    0 d<=             \ treat the 4 numbers on the stack as 2 double-length numbers
                      \ and compare [1]
    -                 \ subtract result from counter (-1 is true in Forth)
  loop                \ end loop
;                     \ end word definition    

[1] - Forth has the concept of double length numbers, which are stored on the stack as two single-length numbers (of the form x y, where the value of the double = y * 2^(l) + xwhere l is the size in bits of a single in the forth implementation you're working with).

In this case, I compared the quotient and remainder to 32 (or 29) 0. If the remainder was greater than 0 (year not divisble by month), the first double would be automatically bigger than 32 (or 29) 0 and the result would be false. If the remainder is 0, then it resolves to effectively a regular check of quotient <= 32 (or 29)

Forth (gforth), 61 bytes

: f 0 13 1 do i 2 = 3 * 32 + 1 do over i j * = - loop loop ; 

Try it online!

Saved some bytes by realizing that only February matters in terms of having the correct number of days in the month

Explanation

Forth (at least gforth) comparisons return -1 for true and 0 for false

0                     \ place 0 on top of the stack to use as a counter
13 1 do               \ begin the outer loop from 1 to 12
  i 2 = 3 *           \ if i is 2 place -3 on top of the stack, otherwise 0
  32 + 1 do           \ begin the inner loop from 1 to 31 (or 28)
    over              \ copy the year from stack position 2 and place it on top of the stack
    i j * = -         \ multiply month and day compare to year, subtract result from counter 
  loop                \ end the inner loop
loop                  \ end the outer loop

reffu

Posted 2018-04-13T14:31:39.840

Reputation: 1 361

2

Retina 0.8.2, 55 bytes

..
$*
(?<=^(1{1,12}))(?=(?(?<=^11$)\1{0,27}|\1{0,30})$)

Try it online! Takes a two-digit year; add 1 byte to support 4-digit years. Explanation: The first stage simply converts to unary. The second stage starts by matching 1 to 12 characters before the match position, representing the month, and then attempts to look ahead for a whole number of repetitions of that month. However, the lookahead contains a conditional, which chooses between up to 27 or 30 further repetitions depending on the month. The count of match positions is then the desired result.

Neil

Posted 2018-04-13T14:31:39.840

Reputation: 95 035

2

C (gcc), 65 60 59 bytes

d(a,t,e){for(t=0,e=13;e-->1;)t+=a%e<1&a/e<(e-2?32:29);a=t;}

Port of user202729's Java answer. Try it online here. Thanks to Jonathan Frech for golfing 1 byte.

O.O.Balance

Posted 2018-04-13T14:31:39.840

Reputation: 1 499

a=0,m=13;for(; ~> for(a=0,m=13;. – Jonathan Frech – 2018-06-30T12:23:50.197

@JonathanFrech Thanks for pointing that out, I have edited. – O.O.Balance – 2018-06-30T14:56:56.797

2

R, 22 122 bytes

x=scan();substr("122324243426133415153317223416132126011504033106131204241006003213011306002122042005101305111014012",x,x)

Try it online!

Decided to go with a lookup table approach. Input year needs to be 2 digits.

Robert S.

Posted 2018-04-13T14:31:39.840

Reputation: 1 253

1Also on TIO you can hit the "link" button and it will auto-format the answer for you. Thanks to Dennis for setting it up! – Giuseppe – 2018-07-19T23:51:42.313

You can remove the initial if, since input can be either 2-digit or 4-digit, your choice (so you can choose to accept only 2-digit input). But it looks like the code considers every month to contain 31 days, so for eg., 62 (for 2062) returns 1 where it should return 0. – sundar - Reinstate Monica – 2018-07-20T13:16:10.160

2I misunderstood. That being said, I'm pretty sure the lookup table would have to be included in the byte count. – ngm – 2018-07-20T16:46:38.617

@ngm I also was not sure if the lookup table needed to be included, but I will add it to the byte count just to be safe. – Robert S. – 2018-07-20T16:51:25.337

I'm still not sure what all the rules are! – ngm – 2018-07-20T16:53:39.187

2

J, 29 bytes

1#.(,x*i."+29+3*2~:x=.i.13)=]

Try it online!

How it works

1#.(,x*i."+29+3*2~:x=.i.13)=]    Input: year (2-digit, 1..99)
                   x=.i.13       array of 0..12; assign to x
                2~:              1 1 0 1 .. 1
              3*                 3 3 0 3 .. 3
           29+                   32 32 29 32 .. 32
       i."+                      for each item of above, generate a row 0 .. n
    ,x*                          each row times 0 .. 12 and flatten
                           =]    1 for each item == input, 0 otherwise
1#.                              sum

Tried hard to get under 2 times Jelly solution :)

Side note

If someone really wants to hardcode the 99-digit data, here's a bit of information:

Divide the 99-digit into chunks of 2 digits. Then the first digit is <4 and the second <8, which means five bits can encode two numbers. Then the entire data can be encoded in 250 bits, or 32 bytes.

Bubbler

Posted 2018-04-13T14:31:39.840

Reputation: 16 616

1

Java (JDK 10), 79 72 70 bytes

y->{int a=0,m=13;for(;m-->1;)a+=y%m<1&&y/m<(m==2?29:32)?1:0;return a;}

Try it online!

user202729

Posted 2018-04-13T14:31:39.840

Reputation: 14 620

@Shaggy Thanks! (leftover from previous version where I loop over all days) – user202729 – 2018-04-13T16:24:29.523

If you change && to & it's the same answer as OlivierGrégoire's Java answer, although he has answered 19 minutes earlier. – Kevin Cruijssen – 2018-04-16T06:47:16.697

@KevinCruijssen Random coincidence. Although my version is a bit worse (unnecessary use of ternary). – user202729 – 2018-04-16T11:30:56.447

1

Haskell, 61 51 bytes

f y=sum[1|i<-[96..508],mod(div i 32)13*mod i 32==y]

Try it online!

Inspired by xnor's Python 2 answer and Laikoni.

Asone Tuhid

Posted 2018-04-13T14:31:39.840

Reputation: 1 944

1

52 bytes: f y=sum[1|i<-[1..12],mod y i<1,div y i<29+mod i 2*3] Try it online!

– Laikoni – 2018-04-14T11:04:17.453

1

JavaScript (Node.js), 108 bytes

a=>'0122324243426133415153317223416132126011504033106131204241006003213011306002122042005101305111014012'[a]

f=a=>'0122324243426133415153317223416132126011504033106131204241006003213011306002122042005101305111014012'[a]
o.innerText=[...Array(99)].map((_,x)=>(2001+x++)+` = `+f(x)).join`\n`
pre{column-count:5;width:480px;}
<pre id=o></pre>

user63124

Posted 2018-04-13T14:31:39.840

Reputation:

Brute-force lookup, nice! – BradC – 2018-04-13T20:07:22.563

Welcome to PPCG! – Shaggy – 2018-04-13T21:27:01.120

1

Perl 5, 68 bytes

//;map$\+=$'%++$m==0&&$'/$m<$_,32,29,32,31,32,31,32,32,31,32,31,32}{

Try it online!

Xcali

Posted 2018-04-13T14:31:39.840

Reputation: 7 671

1

Python 3, 132 bytes

This is really quite long of a program but I thought it might be of interest.

All the values are between 0-7 so I encode each number with 3 bits in a long binary string. I tried pasting a raw binary string into my python program but I couldn't get it to work, so I settled on base64 in the file.

I used the following string as a lookup table (ending 7 used for padding): 01223242434261334151533172234161321260115040331061312042410060032130113060021220420051013051110140127

The program takes this string and decodes it as a number, then uses bit shifting to extract the result.

import base64
lambda n:int.from_bytes(base64.b64decode(b'pNRRxYtw01s9Jw4tFYE0QNkYsoRQgYBosEsYBFIRAUgsUkgwFQM='),'big')>>(6306-3*n)&7

66 bytes + 37 byte file = 103 bytes

This reads a binary file called e and avoids using base64.

lambda n:int.from_bytes(open('e','rb').read(),'big')>>(6306-3*n)&7

Here is a hexdump of the read file (without padding):

00000000  a4 d4 51 c5 8b 70 d3 5b  3d 27 0e 2d 15 81 34 40  |..Q..p.[='.-..4@|
00000010  d9 18 b2 84 50 81 80 68  b0 4b 18 04 52 11 01 48  |....P..h.K..R..H|
00000020  2c 52 48 30 0a                                    |,RH0.|

qwr

Posted 2018-04-13T14:31:39.840

Reputation: 8 929

1

Oracle SQL, 115 bytes

select count(decode(sign(decode(l,2,29,32)-y/l),1,1))from t,
xmltable('1to 12'columns l int path'.')where mod(y,l)=0

We may note that it does not really matter how many days in April (and later months), since 100/4 < 28. Also it's not necessary to check whether year is leap or not. We just have to specify that there are 28 days in February (not 29 because that validation will be executed only for 2058 which is not leap) otherwise it may be just 31 for any month.

Other approaches

Oracle SQL (12c Release 2 and later), 151 bytes

select count(to_date(y/l||'-'||l||'-1' default '' on conversion error,'dd-mm-y'))from t,
(select level l from dual connect by level<=12)where mod(y,l)=0

Oracle SQL (12c Release 2 and later), 137 bytes

select sum(validate_conversion(y/l||'-'||l||'-1'as date,'dd-mm-y'))from t,
(select level l from dual connect by level<=12)where mod(y,l)=0

Both solution could have been 8 bytes shorter if we replace (select level l from dual connect by level<=12) with xmltable('1to 12'columns l int path'.') but Oracle throws an exception because of the bug (tested on versions 12.2.0.1.0, 18.3.0.0.0).

SQL> select count(to_date(y/l||'-'||l||'-1' default '' on conversion error,'dd-mm-y'))from t,
  2  xmltable('1to 12'columns l int path'.')where mod(y,l)=0
  3  /
select count(to_date(y/l||'-'||l||'-1' default '' on conversion error,'dd-mm-y'))from t,
*
ERROR at line 1:
ORA-00932: inconsistent datatypes: expected DATE got DATE


SQL> select sum(validate_conversion(y/l||'-'||l||'-1'as date,'dd-mm-y'))from t,
  2  xmltable('1to 12'columns l int path'.')where mod(y,l)=0
  3  /
select sum(validate_conversion(y/l||'-'||l||'-1'as date,'dd-mm-y'))from t,
*
ERROR at line 1:
ORA-43909: invalid input data type

The only case in both solution when year does matter is 2058 which is non-leap so literal '-1' was used to specify non-leap year.

Oracle SQL, 128 bytes

select count(d)from t,(select date'1-1-1'+level-1 d from dual connect by level<365)
where to_char(d(+),'mm')*to_char(d(+),'dd')=y

Oracle SQL, 126 bytes

select substr('122324243426133415153317223416132126011504033106131204241006003213011306002122042005101305111014012',y,1)from t

Update

Oracle SQL, 110 bytes

select-sum(least(sign(y/l-decode(l,2,29,32)),0))from t,
xmltable('1to 12'columns l int path'.')where mod(y,l)=0

Oracle SQL, 108 bytes

select sum(decode(sign(decode(l,2,29,32)-y/l)*mod(y+1,l),1,1))from t,
xmltable('1to 12'columns l int path'.')

Spark SQL, 137 bytes

select count(cast(regexp_replace(concat_ws('-','2001',l,y/l),'.0$','')as date))
from(select explode(array(1,2,3,4,5,6,7,8,9,10,11,12))l),t

Spark 2.3+ SQL, 126 bytes

(replace function becomes available)

select count(cast(replace(concat_ws('-','2001',l,y/l),'.0')as date))
from(select explode(array(1,2,3,4,5,6,7,8,9,10,11,12))l),t

Dr Y Wit

Posted 2018-04-13T14:31:39.840

Reputation: 511

1

PHP, 73 bytes

Using pipe input and php -nR:

for(;++$m<13;$d=1)while($d<25+($m-2?$m>4?:7:4))$c+=$argn==$m*$d++;echo$c;

Try it online!

PHP, 76 bytes

Using command line arg input php dm.php 18:

for(;++$m<13;$d=1)while($d<25+($m-2?$m>4?:7:4))$c+=$argv[1]==$m*$d++;echo$c;

Try it online!

Iterative approach. Since the only leap year to look at is 2 * 29 = 58, and 2058 is not a leap year there's no need to consider leap year in the Feb days. And since wraparound is not a concern -- from April on, any day greater than 25 will exceed 100 we just say the rest of the months only have 25 days.

Input is 2 digit year via command line (-10 bytes as program, thx to suggestion from @Titus).

OR:

PHP, 101 bytes

$y=$argv[1];for($d=strtotime("$y-1");date(Y,$d)==$y;$d+=86400)eval(date("$\x+=j*n=='y';",$d));echo$x;

Try it online!

Still iterative but using PHP's timestamp functions. Accepts year as four digit number. Thx to @Titus for suggestion of using strtotime() instead of mktime().

640KB

Posted 2018-04-13T14:31:39.840

Reputation: 7 149

First version fails for 4-digit years, second fails for two-digit. But nice thinking. Try $m<5?$m-2?31:28:25 for the first and $d=strtotime("$y-1") for the second – Titus – 2019-02-04T18:30:15.157

Uhm ... Why did you put the y in the eval in quotes? – Titus – 2019-02-04T18:37:19.120

@Titus because PHP7 now treats digits preceeded with 0 as octal, so 08 and 09 are actually not valid. https://tio.run/##K8go@G9jXwAkU5Mz8hUMFWxtFQwsrP//BwA Using the date() function you can only get a 2 digit, zero-padded year.

– 640KB – 2019-02-04T18:39:30.807

Bummer! of course. – Titus – 2019-02-04T18:41:54.693

I underestimated the mktime function. two digits are ok for second; but Input can be a 2 or 4-digit numeric year. doesn´t mention it´s your choice. Btw you may want to submit programs; they´re usually shorter than functions. – Titus – 2019-02-04T18:46:53.797

1@Titus, updated second version using strtotime() instead of mktime() and re-implemented as program, -7 bytes. Also, I looked at the majority of the submissions, including the top voted ones, will only accept year as either 2 or 4 digits, so I'm going to take that to mean it is up to submitter. Thx again for the suggestions! – 640KB – 2019-02-04T19:56:05.040

0

Japt -x, 18 bytes

Takes input as an integer in the range 1-99.

346Ç=ÐUTZ)f *ÒZÎ¥U

Try it

As with my JS solution, takes advantage of the fact that JavaScript's Date will rollover to the next month, and continue doing so, if you pass it a day value that exceeds the number of days in the month you pass to it so, on the first iteration, ÐUTZ tries to construct the date yyyy-01-345 which becomes yyyy-12-11, or yyyy-12-10 on leap years. We don't need to check dates after day 345 that as 12*11+ results in a 3-digit number.

346Ç=ÐUTZ)f *ÒZÎ¥U     :Implicit input of integer U
346Ç                   :Map each Z in the range [0,346)
    =                  :  Reassign to Z
     ÐUTZ              :    new Date(U,0,Z) - months are 0-indexed in JS
         )             :  End reassignment
          f            :  Get the day of the month
            *Ò         :  Multiply by the negation of bitwise NOT of
              ZÎ       :  Get 0-based month of Z
                ¥U     :  Test for equality with U
                       :Implicitly reduce by adition and output

Shaggy

Posted 2018-04-13T14:31:39.840

Reputation: 24 623

0

PHP, 74 70 bytes

while(++$m<13)for($d=$m<5?$m-2?31:28:25;$d;)$n+=$d--*$m==$argn;echo$n;

accepts two-digit years only.

I adopted gwaugh´s considerations and golfed them; my 1st approach was longer than his (92 bytes):

for($y=$argn%100;++$m<13;)for($d=$m-2?30+($m+$m/8)%2:29-($y%4>0);$d;)$n+=$d--*$m==$y;echo$n;

%100 allows to use 4-digit years.


Run as pipe with -nR or try them online.

Titus

Posted 2018-04-13T14:31:39.840

Reputation: 13 814

You can save 4 bytes by removing the %100 and only taking 2 digit input, which is OK: https://codegolf.stackexchange.com/questions/162137/date-multiplying-challenge/179446#comment432764_162137

– 640KB – 2019-02-05T19:44:29.970