Next public holiday
Visual Basic for Applications, 155 or 118 bytes
Version 1 - locale-independent, 155 bytes
Function h(d)
For i=0To 9
h=Array(0,1,3,31,38,192,275,276,277,282)(i)+42454-DateSerial(16,Val(Right(d,2)),Val(Left(d,2)))
If h>=0Goto 9
Next
9 End Function
Version 2 - locale-dependent, 118 bytes
Function h(d)
For i=0To 9
h=Array(0,1,3,31,38,192,275,276,277,282)(i)+42454-CDate(d)
If h>=0Goto 9
Next
9 End Function
Byte count is for final .BAS file, including linefeed characters. Edited outside standard VBA editor (as it imposes additional spaces and verbose forms of some keywords) - but imports and runs smoothly on any Office Application (to test type e.g. ? h("10/08")
in immediate window, or in Excel use directly in a cell formula).
(EDITED) Initially I chose to use DateSerial
to make the function locale-safe (version 1). As I live in Brazil and thus my system is configured to use "dd/mm/yy" format for dates (just like Australia) I could write a even smaller version by using CDate
instead (version 2). CDate
uses system locale information to convert text into date. I also assumed in this version that the code would only be run during 2016 (if year is omitted (-6 bytes) CDate
assumes current year as per system clock).
The number 42454 on third line is the sum of 42450 that is the numeric representation of 01/01/2016 on VBA, and 84 that is the day-of-the-year for the first holiday. The Array contains day-of-the-year for each holiday (including 01/01/2017) offset by -84 as this takes some digits away. Using 16 instead of 2016 on DateSerial
takes away two more bytes.
Creating an identical array nine times inside the iteration is "bad" code, but works and saves 3 more bytes (one for array name and one for equal sign outside loop, and one more to reference the array inside the loop).
The "missing" spaces between 0 and the following keyword on second and fourth lines are not necessary as they are reintroduced automatically by VBE when the module is imported. Used outdated but byte-cheap If <...> Goto <linenumber>
to break from loop (both If <...> Then Exit For
and If <...> Then Exit Function
use more characters).
Also took advantage of the fact that the function name in VBA behaves as a local variable, and its value is automaticaly returned by the function in the end of execution.
JavaScript (ES6), 131 128 bytes
d=>[56,57,59,87,94,248,331,332,333,338].map(n=>r=r||(q=1454e9+n*864e5-new Date(d[3]+d[4]+`/${d[0]+d[1]}/16`))>=0&&q/864e5,r=0)|r
Explanation
Uses the JavaScript built-in Date
constructor to convert the input string into a number of milliseconds since epoch, then compares this with the number of milliseconds for each public holiday.
It does this by storing the public holidays in an array as the number of days since a reference date. I chose 2016-01-29
for the reference date because the number of milliseconds since epoch can be condensed the shortest for this date. Any number of milliseconds between this day and the next works because the result is rounded down, and keeping the number in the middle avoids daylight saving effects (although the OP's timezone does not have daylight savings). The number of this day is 1453986000000
and rounding it up to 1454000000000
(adding a couple of hours) means it can be written as 1454e9
.
d=>
[56,57,59,87,94,248,331,332,333,338] // list of day offsets from 01/29
.map(n=> // for each public holiday offset n
r=r|| // if r is already set, do nothing
(q= // q = approximate difference in ms
1454e9+n*864e5 // time of public holiday
-new Date(d[3]+d[4]+`/${d[0]+d[1]}/16`) // time of input date
)
>=0&& // if q >= 0
q/864e5, // r = q in days
r=0 // r = result
)
|r // floor and return r
Test
This solution is dependent on the user's timezone. This works in the OP's (and my) time zone (GMT +1000). If you want to test it in a different time zone, adding numberOfHoursDifferentFromGMT1000 * 60 * 60 * 1000
to the reference date number should work. (eg. GMT +0430 would be -5.5 * 60 * 60 * 1000 + 1454e9+n*864e5
)
var solution = d=>[56,57,59,87,94,248,331,332,333,338].map(n=>r=r||(q=1454e9+n*864e5-new Date(d[3]+d[4]+`/${d[0]+d[1]}/16`))>=0&&q/864e5,r=0)|r
<input type="text" id="input" value="03/05" />
<button onclick="result.textContent=solution(input.value)">Go</button>
<pre id="result"></pre>
T-SQL, 210, 206, 194 Bytes
(First post here, Hope this is ok, but please be nice :)
Input goes into @i
, caters for both /
and -
as the separator. I'm in Australia, so my date format is the same as @Tas
DECLARE @i CHAR(5)='23-09';DECLARE @c INT=DATEPART(dy,CAST(REPLACE(@i,'-','/')+'/2016' AS DATE))-1;SELECT MIN(b)-@c FROM(VALUES(84),(85),(87),(115),(122),(276),(359),(360),(361))a(b)WHERE b>=@c;
Update varchar
to char
saves 3 bytes plus removed a space :)
Update 2 declare @c
and assign without a select