1   How to sleep well

If I have to choose one Unix command as my favorite, then I am sure sleep is on my top 3 list. Two reasons: a) who doesn’t like sleeping? b) the way you assign the sleep time.

If you have only used sleep in the following forms:

sleep 1
sleep 10

, then you really need to ask yourself, why the heck you haven’t RTFM. Say you are brewing a pot of tea, you run:

sleep 3m && notify_command

A meeting in 2 hours, 15 minutes, you run:

sleep 2h15m && notify_command
# or
sleep 2h 15m && notify_command

See the flexibility of sleep? You can put any amount of sleep time in one run, e.g. sleep {1..60}, sleep will sleep the long all. Don’t you love that?

PS. 1+2+3+…+60 = (1+60)*60/2 = 61*30 = 1830

PS2. try sleep {1..60}{h,m,s}

2   Emulating sleep in Python

I want to use argparse to emulate the same argument input. A final code is hosted on Gist.

Beside the sleep’s number + unit suffix format, I want to also have 01:23:45 format.

In argparse, you can assign type with a checker function, which returns the valid (parsed) value or raise an exception to indicate invalid value.

human_time convert a string into a number in seconds if the input is valid. The first check is for the 01:23:45 format:

TU_SEC = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}
RE_TIME_TAG = re.compile('^(?:(?:(\d+):)?(\d+):)?(\d+)$')
m = RE_TIME_TAG.match(value)
if m:
  matches = zip(m.groups(), ('h', 'm', 's'))
  return sum(int(n or 0) * TU_SEC[unit] for n, unit in matches)

The regular expression catches up to three components in the time tag, they are hour, minute, and second components, respectively. Note that each does not limit to 2-digit, it can be any number of digits. User can input something like 123:30 for 123 minutes and 30 seconds; or 640 for 640 seconds. 1:123:30 will also be a valid input, it may not look a common time format, unnormalized to the speak. I decide to let this one slip through.

n or 0 is to make sure missing components, hh, or hh:mm, will be assigned with 0, int() can not convert None into a value. We need to do so to have a generalized conversion with that generator.

The second part of check is for number + uni suffix format:

TU_SEC = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}
RE_TIME_COMP = re.compile('(\d+)([%s])' % ''.join(TU_SEC.keys()), re.I)

matches = RE_TIME_COMP.findall(value)
if matches:
  return sum(int(n) * TU_SEC[unit] for n, unit in matches)

This part simply gets all matches and convert them into seconds, in the same fashion as previous time format check.

3   Conclusion

There is nothing to conclude. I wrote this piece as a test for urtimer, a very simple countdown timer. I wanted to enable it accepting such time formats as demonstrated above.