1284. A Date Inside Sixteen Bits
A date is to be carried in a single 16-bit value, using the layout older file systems actually used:
bits 15..9 year minus 1900 (7 bits, so 1900 to 2027)
bits 8..5 month (4 bits)
bits 4..0 day (5 bits)
Answer q instructions. P y m d prints the packed value. U v prints the
year, month and day stored in v, reading the fields as they are without
checking that they make a real date.
P 1900 1 1 -> 33
U 545 -> 1901 1 1
P 2027 12 31 -> 65439
## What most people try first
Allocating bits by what feels round: 8 for the year, 4 for the month, 4 for the day. The day fails: a 4-bit field holds 0 to 15 and days run to 31, so every date after the 15th of a month is corrupted. The widths have to come from the RANGES, and the ranges here are 128 years, 12 months and 31 days, needing 7, 4 and 5 bits.
Those sum to 16 exactly, which is not a coincidence: the format was designed backwards from a 16-bit container, which is why the year range is a 128-year window starting at an epoch rather than a full year number. A 4-digit year alone would need 11 bits and leave only 5 for everything else.
## The arithmetic
pack: v = ((y - 1900) << 9) | (m << 5) | d
unpack: y = 1900 + ((v >> 9) & 127)
m = (v >> 5) & 15
d = v & 31
The offsets are running totals of the widths from the bottom: day at 0, month at
0 + 5 = 5, year at 5 + 4 = 9. The masks are 2^5 - 1 = 31,
2^4 - 1 = 15 and 2^7 - 1 = 127.
## The epoch offset is part of the field, not of the value
Subtracting 1900 before shifting and adding it back after masking is what makes the 7-bit field enough. It is easy to get this half right, by subtracting on the way in and forgetting on the way out, and the symptom is dates in the 1970s coming back as the year 70. That bug is worth recognising because it is the whole of the Y2K problem in miniature: a field sized for a window, and code that forgets which window.
## Unpacking does not validate
U 65535 has all sixteen bits set, so the month field reads 15 and the day
field 31. There is no fifteenth month, and the required output is
2027 15 31 anyway. Unpacking reports what the bits SAY; validating is a
separate step, and conflating the two is how a corrupt record becomes a crash
somewhere far away instead of an error at the boundary.
## Width
Sixteen bits exactly, so the packed value runs from 0 to 65535. That fits in a
signed 32-bit integer, limit 2147483647, with fifteen bits to spare, and even
in a signed 16-bit integer it would not, since that stops at 32767: a short
would turn 65439 negative. Nothing here needs 64 bits.
JavaScript is safe with plain Numbers, because every value involved is below
2^16 and << only truncates above bit 31.
Constraints - `1 ≤ q ≤ 100000` - `1900 ≤ y ≤ 2027`, `0 ≤ m ≤ 15`, `0 ≤ d ≤ 31` - `0 ≤ v ≤ 65535`
Input
The first line contains an integer q.
Each of the next q lines is either P y m d or U v.
Output
For each P print one integer on its own line: the packed 16-bit value. For each U print three integers on one line separated by single spaces: the year, the month and the day as stored, without validation.
Hints
Four rungs, in order. The last two open once you have submitted an attempt. A wrong one counts.