3

I have a set of date/time strings in the YYYYMMDDHHMMSS format that I want to convert to something readable by the date utility. Usually, I can do something like:

date -d "2010-10-01 12:34:56"

However, date does not like the YYYYMMDDHHMMSS:

date -d "20100101123456"..invalid date

So, I probably need to refine the string to be in the prior format. I'm thinking sed is the answer, but it gets ugly very fast. I'm quite certain my strings will be the proper format, so how do I easily convert them?

Cascabel
  • 479,068
  • 72
  • 370
  • 318
User1
  • 39,458
  • 69
  • 187
  • 265
  • I amended your title slightly. Looks like you're trying to get it readable by `date`, not by bash; bash doesn't know anything about reading dates. – Cascabel Nov 16 '10 at 18:36

6 Answers6

13

date doesn't allow "YYYYMMDDHHMMSS", but it does "YYYYMMDD HH:MM:SS", so:

D="20100101123456"
date -d "${D:0:8} ${D:8:2}:${D:10:2}:${D:12:2}"
chris
  • 3,986
  • 1
  • 26
  • 32
4

If the format is totally fixed, you could just do it within bash, chopping up the string:

d=20100101123456
pretty_date="${d:0:4}-${d:4:2}-${d:6:2} ${d:8:2}:${d:10:2}:${d:12:2}"
# 2010-01-01 12:34:56
...

I wouldn't bother trying to use regex - like you said, the pattern gets ugly fast. A lot of repetition of ([0-9]{4}), even with extended or perl regex. Or you could be flexible and just match .; no verification.

Cascabel
  • 479,068
  • 72
  • 370
  • 318
  • In shell formatting saves significant time and eliminates the overhead load of pipes and external binaries. There's lots of ${} transformations available. And do not forget use [[ ]] so tests are also ran in the same space. – Mark Stinson Jan 04 '13 at 22:38
2

What's with all of these regular expression answers? The date(1) tool has the ability to use strftime() style date formatting... an an example of converting one date type to another:

$ date -j -f "%Y%m%d%H%M%S" "20100101123456" "+%Y-%m-%d %H:%M:%S"
2010-01-01 12:34:56

So if it's not in the format you want, convert it like that and then use it. If you just want to set it, you can simply do:

$ date -f "%Y%m%d%H%M%S" "20100101123456"
uzi
  • 5,085
  • 2
  • 16
  • 11
  • 3
    That's valid for BSD, but not for GNU. – Dennis Williamson Nov 16 '10 at 19:17
  • So you're right... a rare instance where the GNU tool is inferior. – uzi Nov 16 '10 at 19:27
  • The other instance of inferiority is the license terms. :) – User1 Nov 18 '10 at 14:52
  • Be aware that reading a date (see [`-d`-Option](https://stackoverflow.com/a/39967972/4575793)) is not a part of POSIX date. But as long as you're not working on distributions like Solaris (OP has tagged it linux and not unix) you should be good. :) [See my answer here for a bit more details.](https://stackoverflow.com/a/56854952/4575793) – Cadoiz Oct 12 '21 at 10:27
2

Try this:

echo "20101106213245" | sed -r 's/^.{8}/& /;:a; s/([ :])(..)\B/\1\2:/;ta'

Result:

20101106 21:32:45
  • Insert a space after the eighth character
  • [label a] After a space or colon and the next two characters, add a colon
  • If a replacement was made, goto label a

You want some hyphens, too?

echo "20101106213245" | sed -r 's/^.{4}/&-/;:a; s/([-:])(..)\B/\1\2:/;ta;s/:/-/;s/:/ /'

Result:

2010-11-06 21:32:45
  • Insert a hyphen after the fourth character
  • [label a] After a hyphen or colon and the next two characters, add a colon
  • If a replacement was made, goto label a
  • Change the first colon to a hyphen (2010-11:06:21:32:45 -> 2010-11-06:21:32:45)
  • Change the next colon to a space (2010-11-06:21:32:45 -> 2010-11-06 21:32:45)
Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439
1
 sed -ne 's/\(....\)\(..\)\(..\)\(..\)\(..\)\(..\)/\1-\2-\3 \4:\5:\6/p'

I admit it'S a mouthful. All the .'s should optimally be [0-9] or \d, though I don't remember if sed supports the latter.

Ulrich Schwarz
  • 7,598
  • 1
  • 36
  • 48
  • Generally `sed` does not support Perl shorthands like `\d`, `\s`, `\t`, etc but you can say `d='[0-9]'; sed -ne "s/\\($d$d$d$d\\)\\($d$d\\)\\($d$d\\)\\($d$d\\)\\($d$d\\)\\($d$d\\)"'/\1-\2-\3 \4:\5:\6/p'` (though notice how the double quotes force the backslashes to require doubling; you can't use single quotes because then the shell would not expand the value of `$d`). – tripleee Mar 07 '18 at 13:27
  • tbh I find this more readable then [this one](https://stackoverflow.com/a/4198321/4575793), +1 – Cadoiz Oct 12 '21 at 10:26
0

Either busybox date or bsd date accept a description of the input format.

Busybox is a GNU small utility, easy to install.

The bsd format has been covered in another answer, so here is busybox:

$ busybox date -D "%Y%m%d%H%M%S" -d "20100101123456" +'%Y-%m-%d %H:%M:%S'
2010-01-01 12:34:56
Cadoiz
  • 1,446
  • 21
  • 31