[go: up one dir, main page]

Menu

[r1]: / idl_lib / time_lib.new  Maximize  Restore  History

Download this file

886 lines (793 with data), 27.9 kB

;+*************************************************************************
;
; purpose:	A library of routines for working with dates and times.
;		Most of the routines are fairly straightforward.  Any time
;		values fed to these routines must be a structure having six
;		fields: year, month, day, hour, minute, second in that order
;		(largest unit to smallest)  A structure of this type is 
;		defined in the first routine.
;
; common_blocks: y2k_fix--this common block contains one variable
;			which specifies how to handle two-digit years.
;			Any years above this value are considered to be
;			from the 1900s, while those below are considered
;			to be from after 2000.
;
; dependencies: none
;
; written by:	Peter Mills (peteymills@hotmail.com)
;
; last modified:	February 23, 2001 (last modified for EC)
;			August 14, 2001: 	removed main routine so it can be compiled
;								from within another module
;			October 9, 2001:	time_compare so it accepts vector arguments
;			October 12, 2001:	added time_now routine
;			2001-11-15:			added "/backwards" keyword to time_array
;			2001-11-21:			new version: implements several fixes:
;								-determines leap years with a look-up table
;								-lumps all common blocks into one and initializes
;									them in the time_str__define procedure
;
;*************************************************************************
;*************************************************************************
;
; 	LIST OF ROUTINES:
;
;_________________________________________________________________________
;
; time_str__define
;
; This subroutine is called to define the structure used to contain arbitrary
; time values.  It contains six fields: year, month, day, hour, minute, 
; and second in order from largest to smallest units.  (See the IDL
; documentation for information on using and defining structures)  Unless
; otherwise noted, all of the routines in this library accept structures
; of this type for time values.
;
;_________________________________________________________________________
;
; n_intervals
;
; description:	Returns the number of time intervals between two times.
;
; usage: 	result=n_intervals(start, finish, interval)
;
; inputs:	start:	the start time
;		finish: the finish time
;		interval: The time interval.  The routine ignores
;		the year and month fields when calculating the number of
;		intervals because of the ambiguity resulting from the fact
;		that years and months vary in length.
;
; output:	A double-precision floating point number containing
;		the number of intervals between start and finish.
;
;_________________________________________________________________________
;
; time_array
;
; description:	Returns an array of evenly-spaced time structures in
;		ascending order.
;
; usage:	result=time_array(start, interval, n [,max=max])
;
; inputs:	start:	the start time
;		interval: the time interval
;		n: an integer containing the number of elements in the array
;		max: an optional keyword parameter telling the routine
;			to stop generating values if the current value
;			exceeds this one.  In this case, n returns the number
;			of time values actually generated.	
;		backwards: set this keyword to make the routine iterate
;			in reverse, with backwards time-steps
;			(add 2001-11-15 at NRL)	
;
; output:	Returns an array of time structures with n elements starting
;		at start with interval spacing.  Note that interval can
;		have its month and year fields filled, but because years
;		and months can vary in length, if both the month and day
;		fields are filled (for example) then there is some ambiguity
;		in the result.  In this function, the units are added on
;		from smallest to largest, while one could just as easily go
;		the other way.
;
;__________________________________________________________________________
;
; time_interval
;
; description: 	Returns the length of the intervals between two times.
;
; usage:	interval=time_interval(start, finish, n)
;
; inputs:	start: The start time
;		finish: The finish time
;		n: The number of intervals
;
; output:	The length of the interval in days, hours, minutes and seconds.
;		Again, because of the ambiguity of using years and months
;		as time units, these fields are left blank.
;
;__________________________________________________________________________
;
; time_compare
;
; description:	Compares two time values.  Will also accept "primitive" IDL
;		variables.  Will accept vector arguments (2001-10-09)
;
; usage:	result=time_compare(time1, time2)
;
; inputs:	time1 and time2 are the two variables to compare.
;
; output:	Returns:	 0 if the two values are the same
;				 1 if the first value is greater
;				-1 if the first value is less than
;		(note: will consider 1980/1/0 as different from 1980/1/1
;		even though these are in some senses the same)
;
;__________________________________________________________________________
;
; read_time
;
; description:	Reads a time value from a string in the following format:
;			year\month\[day[-hour[:minute[:second]]]], 
;		or:
;			hour:minute[:second]
;		where all the fields must contain numerical values and only 
;		the seconds field can contain a decimal point.
;			
; usage:	result=read_time(string, time)
;
; inputs:	string:	a string or an array of strings to convert into 
;		time structures.
;			
; outputs:	If the read was successful and there were no errors in the
;		format then returns a 1, otherwise returns a 0.  Any format
;		errors are printed to standard out.  time returns the time 
;		structure(s).
;
; common blocks: 	Note that the separators can be modified by changing
;			the variables in the common block, "separators"
;			but each of the three separators must be unique.
;
;__________________________________________________________________________
;
; time_string
;
; description:	Converts a time structure into a string in the same format
;		as described above.
;
; usage:	string=time_string(time)
;
; input:	A time structure or an array of time structures.  Will also
;		accept primitive IDL variables and convert them using the
;		default IDL format.
;
; output:	A string in the same format as described above.  Any trailing
;		fields which are zero are truncated.  If all of the year,
;		month and day fields are zero, then they are not displayed.
;
;__________________________________________________________________________
;
; long_to_time
;
; description:	Converts a longword integer into a time structure.  The
;		integer must be in the following format:
;			yymmddhh
;		where each letter denotes a digit, y denotes the digits of
;		the year, m the month, d the day and h the hour.
;
; usage:	result=long_to_time(number)
;
; input:	A longword integer or an array of longword integers.
;
; output:	A time structure or an array of time structures.
;
;__________________________________________________________________________
;
; grads_time
;
; description:	Converts a time structure to a string format readable by
;		GrADs.  Normally, this is in the following format:
;			00:30Z3jan1980
;		to denote 12:30 am on the 3rd of January, 1980.  For more
;		information, see the GrADs manual.  If an integer is passed
;		instead of a time structure, then returns the following format:
;			jan1980
;		where the month is specified by the optional month parameter.
;		See below.
;
; usage:	result=grads_time(time [, month])
;
; inputs:	time: 	A time structure or an array of time structures.
;			Could also be an integer specifying the year.
;		month: 	An optional parameter specifying what month or
;			months to use if only the year is specified by time.
;			If no month is specified, then uses January by default.
;
;___________________________________________________________________________
;
; day_value
;
; description:	Returns a double-precision floating point value
;		containing a time value or array of time values converted to 
;		days only.  This is useful for making plots.
;
; usage:	result=day_value(time, offset)
;
; inputs:	time: 	A time structure or an array of time structures.
;		offset: Day values are calculated relative to this as the
;			starting point.  Must be a scalar.
;
;___________________________________________________________________________
;
; time_now
;
; description:	Returns the current time.
;
; usage:	result=time_now()
;
; created:	2001-10-12 NRL
;
;-***************************************************************************
;

;first we define a structure to hold times:
pro time_str__define
  common time_lib, leap_years, y2kfix, date_sep, time_sep, date_time_sep
  
  struct={time_str, year:0, month:0, day:0, hour:0, minute:0, second:0.0}
  
  initialize_time_lib
end

function time_compare, time1, time2
;compares two time values
;returns:
;0: time1 is equal to time2
;-1: time1 is less than time2
;1: time1 is greater than time2

;  t1=systime(1)
 
  if (size(time1))[2] ne 8 then begin
    return, 1*(time1 gt time2)-1*(time1 lt time2)
  endif

  grt=0
  lst=0
  for i=0, 5 do begin
    grt=not lst and (grt or (time1.(i) gt time2.(i)))
    lst=not grt and (lst or (time1.(i) lt time2.(i)))
  endfor
  
;  t2=systime(1)
;  print, t2-t1

  return, 1*grt - 1*lst
  
end

function time_compare2, time1, time2
;this is theoretically faster than the above, but the
;practical difference is negligible and in some contexts
;will be slower because of idl's array operations
;compares two time values
;returns:
;0: time1 is equal to time2
;-1: time1 is less than time2
;1: time1 is greater than time2

;  t1=systime(1)
 
  if (size(time1))[2] ne 8 then begin
    return, 1B*(time1 gt time2)-1B*(time1 lt time2)
  endif

  n=min([n_elements(time1), n_elements(time2)])
  result=intarr(n)
  for j=0, n-1 do begin
    for i=0, 5 do begin
      if time1[j].(i) lt time2[j].(i) then begin
        result[j]=-1
        break
      endif else if time1[j].(i) gt time2[j].(i) then begin
        result[j]=1 
        break
      endif
    endfor
  endfor
;  t2=systime(1)
;  print, t2-t1
  
  return, result
  
end

;calculate the number of intervals between two times:
function n_intervals, start1, finish1, interval
  days_in_month=[0,31,28,31,30,31,30,31,31,30,31,30,31]

  ;convert start and finish blank (i.e. zero) day or month fields to 1:
  start=start1
  finish=finish1
  if start.month eq 0 then start.month=1
  if start.day eq 0 then start.day=1
  if finish.month eq 0 then finish.month=1
  if finish.day eq 0 then finish.day=1

  comp=time_compare(start, finish)
  if comp eq 2 then begin
    print, "Start date must be less than end date"
    return, 0
  endif

  ;calculate days from start of year in finish:
  n_days1=total(days_in_month[0:finish.month-1])+finish.day
  if finish.month gt 2 and finish.year/4.0-finish.year/4 eq 0 then begin
    n_days1=n_days1+1.0D
  endif
  
  ;calculate days until the end of the year in start:
  n_days2=total(days_in_month[start.month:12])-start.day
  if start.month le 2 and start.year/4.0-start.year/4 eq 0 then begin
    n_days2=n_days2+1.0D
  endif
  
  ;calculate the number of days between the two dates:
  if finish.year gt start.year then begin
    n_leap=(finish.year-1)/4-start.year/4
    n_days=n_days1+n_days2+365D*(finish.year-start.year-1)+n_leap
  endif else begin
    if start.year/4.0-start.year/4 eq 0 then days_in_year=366 $
		else days_in_year=365
    n_days=n_days2+n_days1-days_in_year
  endelse

;  print, n_days1, n_days2, n_days
  
  ;convert to a value in seconds:
  n_seconds=n_days*24.0D*60.0D*60.0D
;  print, n_seconds
  ;add finish hours, minutes and seconds,
  ;subtract start hour, minutes and seconds to next day
  n_seconds=n_seconds+60.0D*(finish.minute+60.0D*finish.hour)+finish.second
;  print, n_seconds
  n_seconds=n_seconds- $
	60.0D*(60.0D*(start.hour)+start.minute)-start.second
;  print, n_seconds
  
  ;convert the interval into seconds:
  ;assume the interval has only day, hour, minute and second values:
  n_sec_int=interval.second + $
	60.0D*(interval.minute+60.0D*(interval.hour+24.0D*interval.day))

;  print, n_seconds, n_sec_int
  
  return, n_seconds/n_sec_int
  
end

;finds the length of the time interval in days, hours, minutes and seconds
;between two times divided into n segments:
function time_interval, start, finish, n
  ;first, find the size in seconds:
  interval={time_str, 0, 0, 0, 0, 0, n}
  seconds=n_intervals(start, finish, interval)

  result={time_str}
  ;now to divide it up into minutes, hours and days:
  result.second=seconds mod 60
  minutes=long(seconds/60L)
  result.minute=minutes mod 60
  hours=minutes/60L
  result.hour=hours mod 24
  result.day=hours/24

  return, result
end
  
;produces a time array counting backwards from start_date:
;(see time_array)
function reverse_time_array, start_date, interval, n, max=max

  days_in_month=[0,31,28,31,30,31,30,31,31,30,31,30,31]

  ta=replicate({time_str}, n)
  ta[0]=start_date
  for i=1L, n-1 do begin
    for j=0, 5 do begin
      ta[i].(j)=ta[i-1].(j)-interval.(j)
    endfor
    if ta[i].second lt 0 then begin
      ta[i].minute=ta[i].minute-fix(ta[i].second)/60-1
      ta[i].second=60+ta[i].second mod 60
    endif
    if ta[i].minute lt 0 then begin
      ta[i].hour=ta[i].hour-ta[i].minute/60-1
      ta[i].minute=60+ta[i].minute mod 60
    endif
    if ta[i].hour lt 0 then begin
      ta[i].day=ta[i].day-ta[i].hour/24-1
      ta[i].hour=24+ta[i].hour mod 24
    endif
    if ta[i].month lt 1 then begin
      ta[i].year=ta[i].year-ta[i].month/12-1
      ta[i].month=12-ta[i].month mod 12
    endif
    ;count through the months until the day field is equal to
    ;or less than the days in the month
    repeat begin
      previous_month=ta[i].month-1
      if previous_month eq 0 then begin
        previous_month=12
        yearof=ta[i].year-1
      endif else begin
        yearof=ta[i].year
      endelse
      max_days=days_in_month[previous_month]
      leap=yearof/4.0-yearof/4
      if previous_month eq 2 and leap eq 0 then max_days=29
;      print, max_days, time_string(ta[i])
      if ta[i].day lt 1 then begin
        ta[i].month=previous_month
        ta[i].year=yearof
        ta[i].day=ta[i].day+max_days
      endif
    endrep until ta[i].day ge 1
    if n_elements(max) eq 1 then begin
      if time_compare(ta[i], max) le 0 then break
    endif
  endfor
  if n_elements(max) eq 1 then n=min([n,i+1])
  return, ta
end

;creates an array of time structures of length n
;starting at start_date spaced with interval
;Note that for some values of interval (i.e. those that have both a day field
;and a month field) the spacings of the dates are ambiguous
;max specifies a maximum value to exit on
;--n is then replaced by the number of time values generated
function time_array, start_date, interval, n, max=max, backwards=backwards

  if keyword_set(backwards) then return, reverse_time_array(start_date, interval, n, max=max)

  days_in_month=[0,31,28,31,30,31,30,31,31,30,31,30,31]

  ta=replicate({time_str}, n)
  ta[0]=start_date
  for i=1L, n-1 do begin
    for j=0, 5 do begin
      ta[i].(j)=ta[i-1].(j)+interval.(j)
    endfor
    if ta[i].second gt 59 then begin
      ta[i].minute=ta[i].minute+fix(ta[i].second)/60
      ta[i].second=ta[i].second mod 60
    endif
    if ta[i].minute gt 59 then begin
      ta[i].hour=ta[i].hour+ta[i].minute/60
      ta[i].minute=ta[i].minute mod 60
    endif
    if ta[i].hour gt 23 then begin
      ta[i].day=ta[i].day+ta[i].hour/24
      ta[i].hour=ta[i].hour mod 24
    endif
    if ta[i].month gt 12 then begin
      ta[i].year=ta[i].year+ta[i].month/12
      ta[i].month=ta[i].month mod 12
    endif
    ;count through the months until the day field is equal to
    ;or less than the days in the month
    max_days=days_in_month[ta[i].month]
    leap=ta[i].year/4.0-ta[i].year/4
    if ta[i].month eq 2 and leap eq 0 then max_days=29
    repeat begin
;      print, max_days, time_string(ta[i])
      if ta[i].day gt max_days then begin
        ta[i].month=ta[i].month+1
        ta[i].day=ta[i].day-max_days
      endif
      if ta[i].month gt 12 then begin
        ta[i].year=ta[i].year+1
        ta[i].month=ta[i].month-12
      endif
      max_days=days_in_month[ta[i].month]
      leap=ta[i].year/4.0-ta[i].year/4
      if ta[i].month eq 2 and leap eq 0 then max_days=29
    endrep until ta[i].day le max_days
    if n_elements(max) eq 1 then begin
      if time_compare(ta[i], max) ge 0 then break
    endif
  endfor
  if n_elements(max) eq 1 then n=min([n,i+1])
  return, ta
end

;reads a string in the format: yyyy-mm-dd/hh:mm:ss.
;or hh:mm:ss
;separators can be custom set, i.e. replace - with / and / with -
;note that there must be three unique types of separators, 
;otherwise it won't work
;exit=0: format or syntax error
;exit=2: range error
function read_time, time_string, time_value

  common separators, date_sep, time_sep, date_time_sep
  if n_elements(date_sep) eq 0 then set_time_sep

  days_in_month=[1000,31,28,31,30,31,30,31,31,30,31,30,31]
  time_value={time_str,0,0,0,0,0,0.0}
  field_limits=[3000, 13, 1001, 24, 60, 60.0]
  field_names=tag_names(time_value)

  on_ioerror, con_error
  exit=1

  fields=str_sep(time_string, date_time_sep, /trim)
  n_fields=n_elements(fields)
  if n_fields gt 2 then begin
    print, "Format error"
    exit=0
  endif

  all_fields=strarr(6)
  if n_fields eq 2 then begin
    fields1=str_sep(fields[0], date_sep, /trim)
    n_fields1=n_elements(fields1)
    if n_fields1 gt 3 then begin
      n_fields1=3
      print, "Format error"
      exit=0
    endif
    fields2=str_sep(fields[1], time_sep, /trim)
    n_fields2=n_elements(fields2)
    if n_fields2 gt 3 then begin
      n_fields2=3
      print, "Format error"
      exit=0
    endif
    all_fields[0:n_fields1-1]=fields1[0:n_fields1-1]
    all_fields[3:n_fields2+2]=fields2[0:n_fields2-1]
  endif else begin
    fields2=str_sep(fields[0], time_sep, /trim)
    n_fields2=n_elements(fields2)
    if n_fields2 eq 1 then begin
      fields1=str_sep(fields[0], date_sep, /trim)
      n_fields1=n_elements(fields1)
      if n_fields1 eq 1 then begin
        print, "Scalar value: ambiguous"
        exit=0
      endif else if n_fields1 gt 6 then begin
        n_fields1=6
        print, "Format error"
        exit=0
      endif
      all_fields[0:n_fields1-1]=fields1[0:n_fields1-1]
    endif else begin
      if n_fields2 gt 6 then begin
        n_fields2=6
        print, "Format error"
        exit=0
      endif else if n_fields2 eq 1 then begin
        print, "Scalar value: ambiguous"
        exit=0
      endif
      all_fields[min([3, 6-n_fields2]):min([5, n_fields2+2])] = $
		fields2[0:n_fields2-1]
    endelse
  endelse

  ;read in each value from the field:
  for i=0, 5 do begin
    value=time_value.(i)
    if all_fields[i] ne "" then reads, all_fields[i], value
    time_value.(i)=value
    ;check bounds of each field as it is converted:
    if value ge field_limits[i] or value lt 0 then begin
      print, field_names[i], " field out of bounds"
      exit=2
    endif
  endfor

  ;check the bounds of the month field:
  if time_value.month le 12 then begin
    if time_value.month eq 2 and time_value.year/4.0-time_value.year/4 eq 0 then begin
      if time_value.day gt 29 then begin
        print, field_names[2], " field out of bounds"
        exit=2
      endif
    endif else if time_value.day gt days_in_month[time_value.month] then begin
      print, "Day field out of bounds"
      exit=2
    endif
  endif

;  if time_value.month eq 0 and time_value.year ne 0 then begin
;    print, "Illegal date"
;    exit=2
;  endif

  return, exit

  con_error: print, "Conversion error"
  return, 0

end

;converts a time structure or array to the format:
;yyyy-mm-dd/hh:mm:ss. or, if year, month and day field are zero, hh:mm:ss.
;again, separators can be custom-set
function time_string, time_value
  common separators, date_sep, time_sep, date_time_sep
  
  if n_elements(date_sep) eq 0 then set_time_sep

  if (size(time_value[0]))[2] ne 8 then return, string(time_value)

  sep=["", date_sep, date_sep, date_time_sep, time_sep, time_sep]

  n_times=n_elements(time_value)
  return_str=strarr(n_times)
  for arr_ind=0, n_times-1 do begin
    if time_value[arr_ind].year ne 0 or time_value[arr_ind].month ne 0 $
		or time_value[arr_ind].day ne 0 then begin
      return_str[arr_ind]=string(time_value[arr_ind].year, format='(i0)')
      for n=5, 1, -1 do begin
        if time_value[arr_ind].(n) ne 0 then break
      endfor
      for i=1, min([n,4]) do begin
        return_str[arr_ind]=return_str[arr_ind]+ $
		string(sep[i], time_value[arr_ind].(i), $
		format='(a,i2.2)')
      endfor
      if n eq 5 then begin
        return_str[arr_ind]=return_str[arr_ind]+string(time_sep, $
		time_value[arr_ind].second, format='(a,f5.2)')
      endif
    endif else begin
      return_str[arr_ind]=string(time_value[arr_ind].hour, time_sep, $
		time_value[arr_ind].minute, time_sep, $
		time_value[arr_ind].second, format='(i2.2,a,i2.2,a,f5.2)')
    endelse
  endfor
  if n_times eq 1 then return_str=return_str[0]
  return, return_str
end

;converts a longword integer to a time structure
;integer is in format: yymmddhh
function long_to_time, long

  common y2kfix, y2kfix
  if n_elements(y2kfix) eq 0 then set_y2Kfix

  ;decompose the time into separate components:
  timevalue=long
  year=fix(timevalue/1000000)
  timevalue=timevalue-year*1000000
  year=year+2000*(year lt y2kfix)
  year=year+1900*(year lt 100 and year ge y2kfix)
;  print, timevalue
  month=fix(timevalue/10000)
;  print, month*10000
  timevalue=timevalue-long(month)*10000
;  print, timevalue
  day=fix(timevalue/100)
  hour=fix(timevalue-long(day)*100)
;  print, year, month, day, hour

  time=replicate({time_str}, n_elements(long))
  time.year=year
  time.month=month
  time.day=day
  time.hour=hour

  return, time
end

;converts to grads time
function grads_time, time, month
  common y2kfix, y2kfix
  if n_elements(y2kfix) eq 0 then set_y2kfix

  month_array=["JAN","JAN","FEB","MAR","APR","MAY","JUN", $
		"JUL","AUG","SEP","OCT","NOV","DEC"]
  
  n=n_elements(time)
  ;now put these values into a string:
  if (size(time))[2] eq 8 then begin
    if n_elements(month) ne 0 then begin
      monthstr=strarr(n)+month_array[month]
    endif else begin
      monthstr=month_array(time.month)
    endelse
    grads_time=strarr(n)
    for i=0, n-1 do begin
      year=time[i].year
      if year lt y2kfix then year=year+2000 $
		else if year lt 100 then year=year+1900
      grads_time[i]=string(format='(I2.2,":",I2.2,"Z",I0,A3,I4)', $
		time[i].minute, time[i].hour, time[i].day, monthstr[i], year)
    endfor
  endif else begin
    monthstr=strarr(n)
    if n_elements(month) ne 0 then monthstr=monthstr+month_array[month] $
		else monthstr=monthstr+month_array[0]
    grads_time=strarr(n)
    for i=0, n-1 do begin
      year=time[i]
      if year lt y2kfix then year=year+2000 $
		else if year lt 100 then year=year+1900
      grads_time[i]=string(format='(A3,I4)', monthstr[i], year)
    endfor
  endelse

  if n eq 1 then grads_time=grads_time[0]
  
  return, grads_time
end

;converts a time structure or an array of time structure to
;a numerical (double precision) day value
;where offset is the starting time
function day_value, time, offset

  n=n_elements(time)
  day=dblarr(n)
  interval={time_str, 0, 0, 1, 0, 0, 0}
  for i=0, n-1 do begin
    day[i]=n_intervals(offset, time[i], interval)
  endfor
  if n eq 1 then day=day[0]

  return, day
end

;the current time
function time_now
  result={time_str}
  timestr=systime()
  field=strsplit(timestr, " ", /extract)
  ;get the month:
  case field[1] of
    "Jan": result.month=1
    "Feb": result.month=2
    "Mar": result.month=3
    "Apr": result.month=4
    "May": result.month=5
    "Jun": result.month=6
    "Jul": result.month=7
    "Aug": result.month=8
    "Sep": result.month=9
    "Oct": result.month=10
    "Nov": result.month=11
    "Dec": result.month=12
    else: print, "Bug in the time_now routine!"
  endcase
  result.day=fix(field[2])
  result.year=fix(field[4])
  hhmmss=strsplit(field[3], ":", /extract)
  result.hour=fix(hhmmss[0])
  result.minute=fix(hhmmss[1])
  result.second=float(hhmmss[2])
  return, result
end

;returns the array indices of the minimum and maximum times
pro time_range, time, min, max
  n=n_elements(time)
  min=0
  max=0
  for i=1, n-1 do begin
    result=time_compare(time[min], time[i])
    if result eq 1 then min=i
    result=time_compare(time[max], time[i])
    if result eq -1 then max=i
  endfor
end

;finds the elapsed time in days, hours, minutes and seconds between two systimes
function elapsed_time, systime1, systime2

  bin_time1=bin_date(systime1)
  bin_time2=bin_date(systime2)
  start={time_str, bin_time1[0], bin_time1[1], bin_time1[2], $
		bin_time1[3], bin_time1[4], bin_time1[5]}
  finish={time_str, bin_time2[0], bin_time2[1], bin_time2[2], $
		bin_time2[3], bin_time2[4], bin_time2[5]}
  print, time_string(start)
  print, time_string(finish)

  n_seconds=n_intervals(start, finish, {time_str, 0, 0, 0, 0, 0, 1})
  print, n_seconds
  seconds=n_seconds mod 60
  minutes=fix(n_seconds/60) mod 60
  hours=fix(n_seconds/60)/60 mod 24
  days=fix(n_seconds/60)/60/24
  return, {time_str, 0, 0, days, hours, minutes, seconds}
end

pro test_elapsed

  desc=['0, button, Start, tag=button', $
	'0, text, , tag=text, width=20']
  base=widget_base()
  form=cw_form(base, desc, /column)
  widget_control, form, /realize
  xmanager, "test_elapsed", form
end

pro test_elapsed_event, event

  widget_control, event.id, get_value=stuff
  print, stuff
  if stuff eq "Start" then begin
    ;get the systime, convert it to native format and display it:
    base=widget_info(event.id, /parent)
    widget_control, base, get_uvalue=systime1, get_value=stuff2
    systime1=systime(1)
;    current_bin=bin_date(systime1)
;    current={time_str, current_bin[0], current_bin[1], current_bin[2], $
;		current_bin[3], current_bin[4], current_bin[5]}
    stuff2.text=string(systime1)
    widget_control, event.id, set_value="Stop"
    widget_control, base, set_uvalue=systime1, set_value=stuff2
  endif else if stuff eq "Stop" then begin
    ;get systime, compare it with the old value, and display it:
    base=widget_info(event.id, /parent)
    widget_control, base, get_uvalue=systime1, get_value=stuff2
    systime2=systime(1)
;    e_time=elapsed_time(systime1, systime2)
    e_time=systime2-systime1
    stuff2.text=string(e_time)
    widget_control, event.id, set_value="Start"
    widget_control, base, set_value=stuff2
  endif
end
   
pro test_time_lib, t

  interval={time_str, 0, 0, 1, 6, 0, 0.0}
  
  start_time={time_str, 1999, 1, 1, 0, 0, 0.0}

  finish_time={time_str, 2001, 3, 1, 0, 0, 0.0}

  n=n_intervals(start_time, finish_time, interval)

  t=time_array(start_time, interval, n+1)

  print, n
;  print, t

end

;set the delimitors for the time "strings":
pro initialize_time_lib

  common time_lib, leap_years, y2kfix, date_sep, time_sep, date_time_sep

  date_sep="/"
  time_sep=":"
  date_time_sep="-"
  
  ;if 2 digit year values are less than this, add 2000
  ;otherwise add 1900
  y2kfix=10
  
  ;set leap years:
  n=3000
  leap_years=bytearr(n)
  leap_years[lindgen(n/4)*4]=1
  leap_years[1600, 1700, 1800, 1900]=0
end