1

I have a requirement to add offset hours to the datetime value.

  1. Get the previous date (e.g. 2023-10-19 00:00:00.000000)

    previous_date=`TZ=TZ+24 date '+%Y-%m-%d 00:00:00.000000'`
    
  2. Calculate the timezone offset in hours and get its absolute value (e.g. 4 hrs during Eastern Daylight Saving)

    offset_hours=$(date '+%:z' | sed 's/[-+]\(.*\)/\1/' | awk -F: '{print int($1 * 3600 + $2 * 60 + $3) / 3600}')
    
  3. Add the offset hours and get the adjusted start date (e.g 2023-10-19 04:00:00.000000000)

    startdateandtime=$(TZ="UTC" date -d "$previous_date $offset_hours hours" '+%Y-%m-%d %H:%M:%S.%N')
    

The first 2 commands work on AIX however the 3rd one which is working on Linux fails on AIX. Need help to achieve this and make the 3rd command work on AIX.

Thank you

8
  • 3
    wait, are you just trying to convert a datetime from one timezone to another? Because if that's the case, you should do that, and not try to add hours manually (that breaks down in so many corner cases!) Commented Oct 20, 2023 at 18:34
  • 1
    There is no -d, --date= flag in the date utility provided by AIX. Unfortunately, it is not very clear to me what you are attempting to accomplish so I am unable to suggest how you might fix it. Commented Oct 20, 2023 at 19:00
  • 1
    You also can't convert dates through timezones using the date command on AIX unless you've got GNU date installed. In your question please explain what you're trying to achieve (not how you think it should be done) because I suspect it'll need a bit of perl or python to do right Commented Oct 20, 2023 at 19:01
  • I have to add offset hours to the UTC time. If the date is 2023-10-19 00:00:00.000000 and the system is running in EDT timeZone, add 4 hrs to it and make it 2023-10-19 04:00:00.000000. As that is what makes the 3rd party API will return me the result for current timeZone. Commented Oct 20, 2023 at 21:03
  • Sorry, I don't understand. "If the date is..." According to whom is the date like that? UTC? The Timezone of that third party service? Your time zone? What does that API really expect? Is that documented somewhere? Commented Oct 20, 2023 at 23:28

1 Answer 1

1

Sounds like you want to convert time stamps from one timezone to another.

Adding a fixed offset it not the right way to go as the offset will change during the year in many timezones because of DST and also across time at the whim of governments who may decide to stop DST, or align to (or be annexed by) another country...

For instance, in New York USA, it may be valid on October 19 2023 to add/remove 4 hours to convert to/from UTC, but it won't be in December 2023, and it may not be any longer in October 2030.

In your approach that parses the output of date +%:z, you're getting the offset from the timezone database, but you're getting it for the current time, not that of the timestamp you're trying to convert which is also invalid.

To convert from UTC time to local time

With GNU date, you'd do:

$ export TZ=America/New_York
$ date -d '2023-10-19 00:00:00.000000 +0000' '+%F %T.%6N'
2023-10-18 20:00:00.000000

Portably, you could use perl:

perl -MPOSIX -MTime::Piece -le '
  $format = "%Y-%m-%d %H:%M:%S";
  for (@ARGV) {
    s{[^.]*}{
      $t = Time::Piece->strptime($&, $format);
      strftime($format, localtime $t->epoch)
    }e;
    print;
  }' '2023-10-19 00:00:00.000000'

On AIX, you should be able to use ksh93's printf builtin:

printf '%(%F %T.%6N)T\n' '2023-10-19 00:00:00.000000 +0000'

Or with zsh if available:

zmodload zsh/datetime
datetime='2023-10-19 00:00:00.000000'
format='%Y-%m-%d %H:%M:%S'
TZ=UTC0 strftime -rs epoch $format ${datetime%.*} &&
  strftime -s t $format $epoch &&
  print -r -- $t${(M)datetime%.*}

To convert from local time¹ to UTC time

With zsh:

zmodload zsh/datetime
datetime='2023-10-19 00:00:00.000000'
format='%Y-%m-%d %H:%M:%S'
strftime -rs epoch $format ${datetime%.*} &&
  TZ=UTC0 strftime -s t $format $epoch &&
  print -r -- $t${(M)datetime%.*}

With ksh93:

datetime='2023-10-19 00:00:00.000000'
format='%Y-%m-%d %H:%M:%S.%6N'
t=${ printf '%(%s)T' "$datetime"; } &&
  TZ=UTC0 printf "%($format)T\n" "#$t"

With perl:

perl -MPOSIX -le '
  $format = "%Y-%m-%d %H:%M:%S";
  for (@ARGV) {
    if (/^(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)(.*)/) {
      print strftime($format, gmtime(mktime($6,$5,$4,$3,$2-1,$1-1900))) . $7;
    }
  }' '2023-10-19 00:00:00.000000'

With GNU date:

t=$(date -d '2023-10-19 00:00:00.000000' +%s.%N) &&
  TZ=UTC0 date -d "@$t" '+%F %T.%6N'

In the America/New_York timezone, they give 2023-10-19 04:00:00.000000.

Between arbitrary timezones

The approaches above can easily be adapted to convert between arbitrary time zones. You just need to set TZ appropriately for the command that parses the input date (strftime -r, date -d, first printf in ksh93) and the one that formats the output date (strftime, date, second printf).

With perl, you'd set the TZ environment variables before parsing and formatting with:

perl -MPOSIX -le '
  $format = "%Y-%m-%d %H:%M:%S";
  for (@ARGV) {
    if (/^(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)(.*)/) {
      $ENV{TZ} = "America/New_York";
      my $t = mktime($6,$5,$4,$3,$2-1,$1-1900);
      $ENV{TZ} = "Asia/Kolkata";
      print strftime($format, localtime($t)) . $7;
    }
  }' '2023-10-19 00:00:00.000000'

¹ Though that local time format is ambiguous as it misses the DST information so the conversion can't be done reliably. For instance 2023-11-05 01:23:00.000000 in the America/New_York timezone will happen twice (at 2023-11-05 05:23:00.000000 UTC and 2023-11-05 06:23:00.000000 UTC).

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.