#!/usr/bin/nawk -f
              # SccsId[] = "@(#)epoch_time.awk 1.3 08/03/04"
              #----------------------------------------------------------------------#
              #                            epoch_time.awk                            #
              # -------------------------------------------------------------------- #
              #                                                                      #
              #   Copyright (c) 2006-2008 by Bob Orlando.  All rights reserved.      #
              #                                                                      #
              #   Permission to use, copy, modify and distribute this software       #
              #   and its documentation for any purpose and without fee is hereby    #
              #   granted, provided that the above copyright notice appear in all    #
              #   copies, and that both the copyright notice and this permission     #
              #   notice appear in supporting documentation, and that the name of    #
              #   Bob Orlando not be used in advertising or publicity pertaining     #
              #   to distribution of the software without specific, written prior    #
              #   permission.  Bob Orlando makes no representations about the        #
              #   suitability of this software for any purpose.  It is provided      #
              #   "as is" without express or implied warranty.                       #
              #                                                                      #
              #   BOB ORLANDO DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS           #
              #   SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY      #
              #   AND FITNESS.  IN NO EVENT SHALL BOB ORLANDO BE LIABLE FOR ANY      #
              #   SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES          #
              #   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER    #
              #   IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,     #
              #   ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF     #
              #   THIS SOFTWARE.                                                     #
              #                                                                      #
              #----------------------------------------------------------------------#
              BEGIN \
              {
                #----------------------------#
                # Process options -h and -z. #
                #----------------------------#
                for (n=1; n<ARGC; n++)
                {
                  if (ARGV[1] == "-z") # Timezone option
                  {
                    if (ARGV[2] !~ /^-?[0-9]+$/)
                    {
                      Usage_and_exit("Time zone must be integer (represents hours)!")
                    }
                    tz_adj  = ARGV[2] * 3600
                    ARGV[2] = ""
                    ARGV[1] = ""
                    shift_ARGV()
                  }
                  else if (ARGV[1] == "-h") # Help
                  {
                    Usage_and_exit()
                  }
                }

                if (ARGV[1] == "") # No options/arguments returns current epoch seconds.
                {
                  print secs_since_epoch() # Since Jan. 1, 1970 00:00:00
                  exit 0
                }

                julian_table()

                #----------------------------------------------------------#
                # Using user supplied yyyymmddhhmiss (+\%Y\%m\%d\%H\%M\%S) #
                #----------------------------------------------------------#
                if (ARGV[1] ~ /[0-9][0-9][0-9][0-9][0-1][0-9][0-3][0-9][0-2][0-9][0-5][0-9][0-5][0-9]/)
                {
                  print secs_since_epoch()
                  exit 0
                }

                #----------------------------------------------------------#
                # Looks like epoch seconds argument.                       #
                #----------------------------------------------------------#
                epoch_sss = ARGV[1] + tz_adj # ET timezone adjustment = 5 (hours)
                days = sprintf("%d",(epoch_sss / 86400))
                sss  = sprintf("%d",(epoch_sss % 86400))
                sub(/^-/,"",sss) # Remove any sign.
                int(sss)

                ddddd = (basedate(1970,01,01) + days)

                yyyymmdd = ddddd_to_yyyymmdd(ddddd)

                hh  =  (sss / 3600.000000)
                sss =  (sss % 3600.000000)
                mm  =  (sss / 60.000000)
                ss  =  (sss % 60)
                printf("%8s%02d%02d%02d\n", yyyymmdd, hh, mm, ss)

                exit 0
              } # E.O.BEGIN
              
              #======================================================================#
              #                     U S E R    F U N C T I O N S                     #
              #                        (in alphabetical order)                       #
              #----------------------------------------------------------------------#
              function basedate(                                               \
                                 YYYY,MM,DD,                                   \
                                 yyyy,cc,ddddd,leapdays,cc_leapdays,accum_days \
                               )
              # -------------------------------------------------------------------- #
              # Globals: julian_days[] and julian_leap[]                             #
              #   Calls: leap_year()                                                 #
              #----------------------------------------------------------------------#
              {
                julian_table() # Start with a new julian table.

                #--------------------------------------------------------#
                # First, decrement the year and get the number of days   #
                # for all the years preceeding it (in the Common Era).   #
                #--------------------------------------------------------#
                yyyy = YYYY
                if ((yyyy - 1) > 0)
                {
                  yyyy--
                  cc          = int(yyyy / 100)
                  ddddd       = yyyy * 365
                  leapdays    = int(yyyy / 4)
                  cc_leapdays = (cc > 0) ? (int(cc / 4)) : 0
                  ddddd       = ddddd + leapdays - cc + cc_leapdays
                  yyyy++
                }
                ddddd += DD

                #--------------------------------------------------------#
                # Add the previous month YTD days to our ddddd.  If it   #
                # is a leap year, assign julian_leap[] to accum_days[].  #
                # Then add in YTD days for previous months of this year  #
                #--------------------------------------------------------#
                if (leap_year(yyyy))
                  for (i=0; i<13; i++) accum_days[i] = julian_leap[i]
                else
                  for (i=0; i<13; i++) accum_days[i] = julian_days[i]
                ddddd += accum_days[MM += 0] # 'MM += 0' removes leading zero

                return (ddddd)
              } # function basedate
              
              #----------------------------------------------------------------------#
              function ddddd_to_yyyymmdd(DDDDD,                   ddddd,yyyy,mmdd,i) #
              # -------------------------------------------------------------------- #
              # Globals: julian_days[] and julian_leap[].                            #
              #----------------------------------------------------------------------#
              {
                yyyy = ddddd = reduce(DDDDD)
                sub(/-.*$/,"", yyyy); yyyy  += 0 # "+= 0" ensures numeric context
                sub(/^.*-/,"",ddddd); ddddd += 0

                if (leap_year(yyyy))
                  for (i in julian_leap)
                    julian[i] = julian_leap[i]
                else
                  for (i in julian_days)
                    julian[i] = julian_days[i]

                #------------------------------------------------------------#
                # Reduce ddddd to month and day (we already have the year).  #
                #------------------------------------------------------------#
                for (i=13; i>0; i--)
                {
                  if (julian[i] < ddddd)
                  {
                  # if (leap_year(yyyy) && i > 2) ddddd++
                    ddddd -= julian[i]
                    mmdd = sprintf("%02d%02d", i, ddddd)
                    break
                  }
                }

                return (yyyy""mmdd)
              } # function ddddd_to_yyyymmdd
              
              #----------------------------------------------------------------------#
              function julian_table()
              #----------------------------------------------------------------------#
              {
                split("0 31 59 90 120 151 181 212 243 273 304 334 365", julian_days)
                split("0 31 60 91 121 152 182 213 244 274 305 335 366", julian_leap)
              }
              
              #----------------------------------------------------------------------#
              function leap_year(YYYY) # YYYY = year.  Returns true|false (1|0).
              #----------------------------------------------------------------------#
              {
                return (((YYYY%4 == 0 && YYYY%100 != 0) || (YYYY%400 == 0)) ? 1 : 0)
              } # function leap_year
              
              #----------------------------------------------------------------------#
              function reduce(DDDDD,           yyyy,ddddd,cc,leapdays,cc_leapdays,i) #
              #----------------------------------------------------------------------#
              {
                for (i=1; ; i++)
                {
                  yyyy        = int(DDDDD / 365) - i
                  ddddd       = DDDDD - yyyy * 365
                  cc          = int(yyyy / 100)
                  leapdays    = int(yyyy / 4)
                  cc_leapdays = (cc > 0) ? (int(cc / 4)) : 0
                  leapdays    = leapdays - cc + cc_leapdays
                  ddddd      -= leapdays
                  yyyy++
                  if (ddddd > 0) break
                }
                return yyyy"-"ddddd
              } # function reduce

              #----------------------------------------------------------------------#
              function secs_since_epoch(ddddd,ddddd_yyyy,sss)
              #----------------------------------------------------------------------#
              {
                #-------------------------------------------------------#
                # Calling date with "+\%Y\%m\%d" (with escaped percent  #
                # signs) avoids hassles with SCCS and percentYpercent.  #
                #-------------------------------------------------------#
                if (ARGV[1] == "")
                  "date +\%Y\%m\%d\%H\%M\%S" | getline yyyymmddhhmiss
                else                                           # yyyymmddhhmiss
                  yyyymmddhhmiss = sprintf("%14s",substr(ARGV[1]"00000000000000",1,14))

                yyyy = substr(yyyymmddhhmiss, 1,4)
                mm   = substr(yyyymmddhhmiss, 5,2)
                dd   = substr(yyyymmddhhmiss, 7,2)
                hh   = substr(yyyymmddhhmiss, 9,2)
                mi   = substr(yyyymmddhhmiss,11,2)
                ss   = substr(yyyymmddhhmiss,13,2)

                ddddd = basedate(yyyy,mm,dd)
                ddddd_yyyy = basedate(1970,01,01)
                ddddd -= ddddd_yyyy

                sss = (ddddd * 86400) + (hh * 3600) + (mi * 60) + ss
                sss += tz_adj

                return sss
              } # function secs_since_epoch
              
              #----------------------------------------------------------------------#
              function shift_ARGV(i,j,k)
              #----------------------------------------------------------------------#
              {
                k = ARGC
                for (i=1; i<=ARGC; i++)
                {
                  if (ARGV[i] == "")     # If the argument is empty, see is we
                  {                      # can shift the next one down to it.
                    for (j=i+1; j<=k; j++)
                    {
                      if (ARGV[j] == "") # If the next one is empty, try the one
                        continue         # following that.
                      ARGV[i] = ARGV[j]  # Once we find an argument, move it down,
                      ARGV[j] = ""       # null where it was, decrement arg counter,
                      break              # can do this with the next argument.
                    }
                  }
                }

                for (i=1; i<=k; i++)     # Adjust ARGC
                  if (ARGV[i] == "")     # If the argument is empty,
                    ARGC--               # decrement ARGC
                return ARGC
              } # function shift_ARGV

              #----------------------------------------------------------------------#
              function Usage_and_exit(SPECIFIC_ERROR)
              #----------------------------------------------------------------------#
              {
                if (SPECIFIC_ERROR) print "\n"SPECIFIC_ERROR

                print "\nPurpose: Return current Unix Epoch time (ssssssssss) or",
                    "\n         convert specified Unix Epoch time to yyyymmddhhmiss",
                    "\n         datetime, or convert yyyymmddhhmiss datetime to",
                    "\n         Unix Epoch seconds.\n",
                    "\n  Usage: epoch_time.awk -h -z [-]hh [yyyymmddhhmiss|ssssssssss]",
                    "\n    e.g. epoch_time.awk [no options or arguments]",
                    "\n         epoch_time.awk 20070121132053",
                    "\n         epoch_time.awk 1169385653"
                exit 1
              }


              #======================================================================#
              #                       D O C U M E N T A T I O N                      #
              #======================================================================#
              #                                                                      #
              #      Author: Bob Orlando (Bob@OrlandoKuntao.com)                     #
              #                                                                      #
              #        Date: May 2, 2006                                             #
              #                                                                      #
              #  Program ID: epoch_time.awk                                          #
              #                                                                      #
              #     Purpose: Return current Unix Epoch time (ssssssssss) or          #
              #              convert an Epoch seconds argument (seconds since        #
              #              January 1, 1970 00:00:00) into yyyymmddhhmiss datetime  #
              #              form -- OR -- convert yyyymmddhhmiss datetime argument  #
              #              into Unix Epoch seconds.                                #
              #                                                                      #
              #              The script uses the host's time zone, but adjustments   #
              #              can be made via the time zone (-z) option.  The optarg  #
              #              is specified in hours and may be specified negatively.  #
              #                                                                      #
              #       Usage: [gn]awk -f epoch_time.awk -- -h -z [-]hh \              #
              #                                        [yyyymmddhhmiss|ssssssssss]   #
              #                                                                      #
              #                 --             = This option must come first for it  #
              #                                  tells Awk to pass on all options    #
              #                                  that follow to the script itself.   #
              #                 -h             = Help (usage brief)                  #
              #                 -z [-]hh       = Timezone adjustment in hours        #
              #                 yyyymmddhhmiss = Converts to epoch seconds           #
              #                 ssssssssss     = Converts to yyyymmddhhmiss datetime #
              #                                                                      #
              #    Examples: 1. epoch_time.awk # No options or argument              #
              #              2. epoch_time.awk          1164718505                   #
              #              3. epoch_time.awk          20061128125505               #
              #              4. epoch_time.awk -- -z  2 1164718505                   #
              #              5. epoch_time.awk -- -z  2 20061128125505               #
              #              6. epoch_time.awk -- -z -2 1164718505                   #
              #                                                                      #
              #    Displays: 1. 1164718505     # Current datetime to Epoch seconds   #
              #              2. 20061128125505 # Epoch seconds to yyyymmddhhmiss     #
              #              3. 1164718505     # yyyymmddhhmiss to epoch seconds     #
              #              4. 20061128145505 # Adjusted by 2 hour timezone         #
              #              5. 1164725705     # Adjusted by 2 hours                 #
              #              6. 20061128105505 # Adjusted by -2 hours                #
              #                                                                      #
              #    Modified: 2008-03-04 Bob Orlando                                  #
              #                 v1.3  * Bug fix: Thanks to Mahir Aydin for           #
              #                         pointing this out and identifying the fix.   #
              #                         The following line was commented out from    #
              #                         ddddd_to_yyyymmdd function:                  #
              #                                                                      #
              #                           if (leap_year(yyyy) && i > 2) ddddd++      #
              #                                                                      #
              #                         The line was "adding one day if the year     #
              #                         is a leap year and the month is after        #
              #                         February, which is unnecessary, since you    #
              #                         already have two separate tables for leap    #
              #                         years and normal years, and [you] use the    #
              #                         correct one."                                #
              #                                                                      #
              #              2007-04-25 Bob Orlando                                  #
              #                 v1.2  * Bug fix: Timezone option (-z).  Changed      #
              #                           if (tz_adj !~ /^[0-9]+$/)                  #
              #                         to                                           #
              #                           if (ARGV[2] !~ /^-?[0-9]+$/)               #
              #                                                                      #
              #              2006-05-02 Bob Orlando                                  #
              #                 v1.1  * Initial release.                             #
              #                                                                      #
              #----------------------------------------------------------------------#
            
Artificial Intelligence is no match for natural stupidity.
©Copyright Bob Orlando, 2006-2011
All rights reserved.
http://www.OrlandoKuntao.com
E-mail: Bob@OrlandoKuntao.com
Last update: Jan. 17, 2011
by Bob Orlando