How old is it roughly?

Write a short program which takes in a positive number of seconds representing an age, and outputs an estimate of that time in English.

Your program must output the least precise amount of time which has passed, among the following metrics and their lengths in seconds:

second = 1
minute = 60
hour   = 60 * 60
day    = 60 * 60 * 24
week   = 60 * 60 * 24 * 7
month  = 60 * 60 * 24 * 31
year   = 60 * 60 * 24 * 365

Examples

input      : output
1          : 1 second
59         : 59 seconds
60         : 1 minute
119        : 1 minute
120        : 2 minutes
43200      : 12 hours
86401      : 1 day
1815603    : 3 weeks
1426636800 : 45 years

As you can see above, after the time of say, 1 day (60 * 60 * 24 = 86400 seconds), we no longer output minute(s) or hour(s), but only days until we surpass the time of one week, and so on.

Consider the given length of time to be an age. For example, after 119 seconds, 1 minute has passed, not 2.

Rules

• No specification for 0 or negative inputs.
• Follow proper pluralization. Every measure greater than 1 must include an s following the word.
• You may not use a pre-existing library which serves the function of the entire program.
• This is a code golf, shortest program wins the internet points.
• Have fun!
• I don't understand how we choose a unit or amount. Do we round?
– xnor
Mar 18 '18 at 2:35
• @xnor we integer divide and use the smallest non-zero value along with its unit (possibly pluralised). Hence 59 -> "59 seconds" and 86401 -> "1 day". Mar 18 '18 at 3:21
• Welcome to PPCG! Nice first challenge. For future reference there is a sandbox which is useful for getting feedback before posting to main. Mar 18 '18 at 3:24
• Note that Do X without Y is discouraged, as well as Non-observable program requirement. Mar 18 '18 at 14:02
• How should we round the numbers? Should 119 seconds be 1 minute or 2 minutes? What about 90? Mar 18 '18 at 14:19

Jelly, 62 bytes

TṀị
“¢<<ð¢‘×\×€0¦7,31,365F⁸:µç“ɲþḣ⁹ḢṡṾDU¤µQƝṁ⁼ẹ»Ḳ¤ṭÇK;⁸Ç>1¤¡”s

A full program printing the result.
(As a monadic link it returns a list of an integer followed by characters)

Try it online!

How?

TṀị - Link 1: list of integers, K; list, V  e.g. [86401,1440,24,1,0,0,0], ["second","minute","hour","day","week","month","year"]
T   - truthy indexes of K                        [1,2,3,4]
Ṁ  - maximum                                    4
ị - index into V                               "day"

“¢<<ð¢‘×\×€0¦7,31,365F⁸:µç“...»Ḳ¤ṭÇK;⁸Ç>1¤¡”s - Main link: integer, N  e.g. 3599
“¢<<ð¢‘                                       - list of code-page indices = [1,60,60,24,1]
\                                     - cumulative reduce with:
×                                      -  multiplication = [1,60,3600,86400,86400]
7,31,365                         - list of integers = [7,31,365]
¦                                 - sparse application...
0                                  - ...to index: 0 (rightmost)
×€                                   - ...of: multiplication for €ach = [1,60,3600,86400,[604800,2678400,31536000]]
F                        - flatten = [1,60,3600,86400,604800,2678400,31536000]
⁸                       - chain's left argument, N    3599
:                      - integer divide         [3599,59,0,0,0,0,0]
µ                     - start a new monadic chain, call that X
“...»               -   compression of "second minute hour day week month year"
Ḳ              -   split at spaces = ["second","minute","hour","day","week","month","year"]
ç                    - call the last link (1) as a dyad - i.e. f(X,["second","minute","hour","day","week","month","year"])
-                             "minute"
Ç           - call the last link (1) as a monad - i.e. f(X,X)
-                             59
ṭ            - tack                        [59,['m','i','n','u','t','e']]
K          - join with spaces            [59,' ','m','i','n','u','t','e']
”s - literal character '
¡   - repeat...
⁸        -   chain's left argument, X  [3599,59,0,0,0,0,0]
Ç       -   call the last link (1) as a monad - i.e. f(X,X)
-                             59
>1     -   greater than 1?           1
;         - concatenate                 [59,' ','m','i','n','u','t','e','s']
- implicit print - smashes to print  "59 minutes"

C, 194180144 128 characters

Thanks to @gastropher for the code reductions. I forgot that C allows for implicit parameters using K&R-style functions! Also thanks to @gmatht for the idea of putting literals inside instead of arrays. I extended that to the characters by abusing taking advantage of wide character/char16_t strings! The compiler doesn't seem to like \1 in its ☺ form though.

f(t,c,d){for(c=7;!(d=t/L"\1<ฐ\1•▼ŭ"[--c]/(c>2?86400:1)););printf("%d %.6s%s\n",d,c*6+(char*)u"敳潣摮業畮整潨牵 慤y†敷步 潭瑮h敹牡",(d<2)+"s");}

Try it online!

Original solution

I split up the arrays into separate lines to make it easier to see the rest of the solution.

char *n[]={"second","minute","hour","day","week","month","year"};
int o[]={1,60,3600,86400,604800,2678400,31536000};
f(int t){int c=7,d;while(!(d=t/o[--c]));printf("%d %s%s\n",d,n[c],d>1?"s":"");}

Try it online!

Running the divisors in order from largest to smallest, we get the coarsest unit of time. The program misbehaves if you give it 0 seconds, but as the specification explicitly excludes this value, I deem that to be acceptable.

• Some tricks can be used to get it down to 183 bytes: Try it online! Mar 18 '18 at 6:46
• Sorry, that one introduced a bug. Proper one at 180 bytes: Try it online! Mar 18 '18 at 6:53
• @gastropner I think the last one has a bug too. '(d<1)' should be '(d<2)'... or '(d<=1)', but lets not go crazy. Mar 18 '18 at 18:05
• @gmatht You are quite right! Mar 18 '18 at 18:11
• OK, last one, I promise. 164 bytes. Mar 18 '18 at 18:32

Try it online!

Ruby, 129 bytes

->n{x=[365*d=24*k=3600,d*31,d*7,d,k,60,1].index{|j|0<d=n/k=j};"#{d} #{%w{year month week day hour minute second}[x]}#{d>1??s:p}"}

Try it online!

Perl 6/Rakudo 138 bytes

I'm sure there's further to go, but for now

{my @d=(365/31,31/7,7,24,60,60);$_/=@d.pop while @d&&$_>@d[*-1];$_.Int~" "~ <year month week day hour minute second>[+@d]~($_>1??"s"!!"")}

Explicate:

{ # bare code block, implicit $_ input my @d=(365/31,31/7,7,24,60,60); # ratios between units$_ /= @d.pop while @d && $_ > @d[*-1]; # pop ratios off @d until dwarfed$_.Int~   # implicitly output: rounded count
" "~  # space
<year month week day hour minute second>[+@d]~ # unit given @d

R, 246 bytes

f=function(x,r=as.integer(strsplit(strftime(as.POSIXlt(x,"","1970-01-01"),"%Y %m %V %d %H %M %S")," ")[])-c(1970,1,1,1,1,0,0),i=which.max(r>0)){cat(r[i],paste0(c("year","month","week","day","hour","minute","second")[i],ifelse(r[i]>1,"s","")))}

Try it online!

This is using time formating instead of arithemtics, just for the hell of it. Maybe others could make this smaller?