Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

how to add 1 day to a date in a string

Brian_Murphy
New Contributor II
4,746 Views

I have a date in "YYYY-MM-DD HH:mm:ss" format with the 19 characters in an integer array.  Is there an easy way to add one day to this?

0 Kudos
23 Replies
GVautier
New Contributor II
4,219 Views

What do you mean by "add 1 day"? Exactly 24 hours or the next day with the same hour because the DST changes will be a different problem .

0 Kudos
andrew_4619
Honored Contributor III
4,219 Views

there is no "easy way". There are many different time date functions and third party code.  One way is:

1) parse the date/time string into integer value for day, year etc

2) use packtimeqq (ifport) to get seconds since start of 1970

3) add 24*60*60 seconds

3) use unpacktimeqq to get new day, month etc

4) re make a date a date string in your  chosen format

I use all my own routines but you need to be aware of leaps years etc

 

0 Kudos
Brian_Murphy
New Contributor II
4,219 Views

Thanks for the reply.

Darn.  unpacktimeqq would be a big help, but for this application it's still not worth that much effort.  I looked at m_time, too, but it would still be too big of a job.  I was hoping for a module that implements a Date data type similar to visual basic.

0 Kudos
GVautier
New Contributor II
4,219 Views

It's the pleasure of Fortran. You have to write your own set of utility functions. Then you can use and reuse it in all of your projects and it will growth with time and experience. And the big advantage is that you have not to wait for an hypothetical fix of bugs, fix them yourself.

0 Kudos
mecej4
Honored Contributor III
4,219 Views

There are many different solutions for this kind of date/time manipulation. An elegant solution is based on the module at https://wavebitscientific.github.io/datetime-fortran/ . The following code demonstrates how to add 1 day to today's date and print the result in the same string format as you specified.

program xdatetime
implicit none
character(19) :: dtstr

dtstr = '03:31:2020 07:32:15'   

call addAday(dtstr)
print '(1x,A)',dtstr

end program

subroutine addAday(dtstr)   ! Add 1 day to date-time represented in string dtstr
use datetime_module
implicit none
character(19), intent(in out) :: dtstr
type(datetime)  :: start, nextday
type(timedelta) :: dt
integer iy,imo,id,ih,im,is

read(dtstr,'(i2,1x,i2,1x,i4,1x,i2,1x,i2,1x,i2)')imo,id,iy,ih,im,is      ! parse fields
start = datetime();                                                     ! default initialization
start = datetime(iy,imo,id,ih,im,is)                                    ! put new values into structure

dt = timedelta()          ! Initialize to zero deltas
dt = timedelta(1,0,0,0,0) ! 1 day, 0 hours and 0 minutes

nextday = datetime()      ! Initialize to default values
nextday = start + dt      ! new date-time = old date-time + 1 day difference

dtstr = nextday%strftime('%m:%d:%Y %H:%M:%S')

return
end subroutine

The output from the program:

 04:01:2020 07:32:15

 

0 Kudos
Brian_Murphy
New Contributor II
4,219 Views

Thanks, mecej4.  Someone(s) must have spent a lot of effort developing that code.

I tried to build your sample program using visual studio and got the following linker error.  I looked in datetime.f90  at the strptime function, and I don't see what the linker is complaining about.  Did you run it with Intel Fortran or some other fortran?

Error LNK2019: unresolved external symbol _strptime referenced in function _MOD_DATETIME_mp_STRPTIME        mod_datetime.obj

 

0 Kudos
mecej4
Honored Contributor III
4,219 Views

You need to include in your build the C++ source file strptime.cpp, which is in a different directory in the same distribution. See the very last file in the directory listing at https://github.com/wavebitscientific/datetime-fortran

0 Kudos
jimdempseyatthecove
Honored Contributor III
4,219 Views

Also, if your date string is coming in from an external source, you will have to adapt your input conversion to handle cases where there is not leading zero. Worst case might be ...3:1:2020 7:32:15 (m:d:yyyy h:mm:ss)

Even when told "the input format is this way..." add exception code to your program. It is much easier to deal with potential problems now, rather than later should your program be in use by (many) other people.

Also, data may be submitted from different geographical areas where they submit dd:mm instead of mm:dd

Jim Dempsey

 

0 Kudos
Brian_Murphy
New Contributor II
4,219 Views

Hmmm.  cpp and f90 files in the same project?  This is uncharted water for me.  I created strptime.cpp containing that code, and added it to the fortran project in visual studio.  Not surprisingly, I still get the same linker error because the c++ file isn't getting compiled.  What am I missing?  Do i need a custom build step to compile the cpp file?  My Intel license includes clang++.exe and clang-cl.exe in the Intel bin folder.

Jim - in this application the input string will always be 19 characters.  So I believe the leading zero, like 03 for march, will always be there.  But I should double check that to make sure.

0 Kudos
jimdempseyatthecove
Honored Contributor III
4,219 Views

>>in this application the input string will always be 19 characters.

Put that on a post-it note as a future reminder.

Jim Dempsey

0 Kudos
mecej4
Honored Contributor III
4,219 Views

Compile the C++ source with the command

cl /O2 /MD /c /EHsc strptime.cpp

Then add the resulting file strptime.obj to your link line. There are many other ways, as well, but this one is quite simple.

0 Kudos
mecej4
Honored Contributor III
4,219 Views

One thing to keep in mind: the separator used by Windows for displaying dates is '/', not ':' -- the latter is used only for time-of-day strings.

0 Kudos
Brian_Murphy
New Contributor II
4,219 Views

Thanks.  I got the sample program working with /libs:dll but get several linker errors with /libs:static.  What am I missing?  Again, I'm building with Visual Studio.  Do I need to specify an Additional Library Directory?  I tried adding C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.24.28314\lib\x86\ where msvcrt.lib is located, but that didn't help.

Error		error LNK2019: unresolved external symbol __except_handler4_common referenced in function __except_handler4		MSVCRT.lib(chandler4gs.obj)		
Error		fatal error LNK1120: 2 unresolved externals		Release\DateTime.exe		
Error		error LNK2019: unresolved external symbol __imp__setlocale referenced in function _strptime		strptime.obj

 

0 Kudos
mecej4
Honored Contributor III
4,219 Views

Here is a simpler solution, using only Fortran. Please modify to suit the format used for dates and times in the data file.

The derived type datetype in this library does not provide for seconds and milliseconds.

program xaddday
character(19) :: dtstr

dtstr = '03:31:2020 11:56:45'   ! US convention: mm:dd:yyyy hh:MM:ss

call addAday(dtstr)
print '(1x,A)',dtstr

end program

subroutine addAday(dtstr)   ! Add 1 day to date-time represented in string dtstr
use libdate                 ! http://flibs.sourceforge.net/libdate.html
implicit none
character(19), intent(in out) :: dtstr
type(datetype) :: adate, delta, bdate
integer iy,imo,id,ih,im

read(dtstr,'(i2,1x,i2,1x,i4,1x,i2,1x,i2)')imo,id,iy,ih,im               ! parse fields
adate = datetype(iy,imo,id,ih,im)
delta = datetype(0,0,1,0,0)                                             ! 1 day
bdate = adate + delta
call format_date(bdate,'mm:dd:yyyy HH:MM',dtstr(:16))
return
end subroutine

 

0 Kudos
LeonardB
New Contributor I
4,219 Views

Windows filetime structure is an INTEGER(8), stored as two INTEGER(4). 

It is a count of 100 ns from 01/01/1601 00:00:00.  Using this, time manipulation becomes quite easy.

module Tfunk
        use kernel32 , only: T_SYSTEMTIME 
        implicit none
        integer, parameter:: T_time=8
        integer, parameter:: T_dataindex=8
        integer(T_time),parameter:: Second=10000000_8

    
    contains
    
integer(8) function I8TimeFromSystemTime(systemtime)
    use kernel32, only: T_filetime, T_systemtime, SystemTimeToFiletime
    implicit none
    type(T_systemtime),intent(in):: systemtime
    type(T_filetime)::filetime
    integer(T_time):: I8time
    integer::iret
    pointer(locI8time,I8time)
    iret=SystemTimeToFiletime(systemtime,filetime)
    locI8time=loc(filetime)
    I8TimeFromSystemTime=I8time
end function I8TimeFromSystemTime

function SystemtimeFromI8Time(I8time)
    use kernel32, only: T_filetime,T_systemtime,FileTimeToSystemTime
    implicit none
    type(T_systemtime)::SystemtimeFromI8Time
    integer(8),intent(in):: I8Time
    type(T_filetime)::filetime
    type(T_systemtime):: systemtime
    pointer(locft,filetime)
    integer:: iret
    locft=loc(I8Time)
    iret=FileTimeToSystemTime(filetime,systemtime)
    SystemtimeFromI8Time=systemtime
end function SystemtimeFromI8Time

integer(8) function GetSystemtimeAsI8time()
    use kernel32, only:  T_filetime,T_systemtime,GetSystemtimeAsFiletime
    integer(8):: i8time
    pointer(LocI8time,i8time)
    
    type(T_filetime):: ftime
    call GetSystemTimeAsFileTime(ftime)
    LocI8time=loc(ftime)
    GetSystemtimeAsI8time=i8time
end function GetSystemtimeAsI8time

integer(8) function GetLocaltimeAsI8time()
    use kernel32, only:  T_filetime,T_systemtime,GetSystemtimeAsFiletime,FileTimeToLocalFileTime
    integer:: iret
    integer(8):: i8time
    pointer(LocI8time,i8time)
    
    type(T_filetime):: ftime,ltime
    call GetSystemTimeAsFileTime(ftime)
    iret=FileTimeToLocalFileTime( ftime,ltime)
    LocI8time=loc(ltime)
    GetLocaltimeAsI8time=i8time
    end function GetLocaltimeAsI8time

    end module tfunk 
    
    program main
    use Tfunk
    implicit none
    
    
    !   T_systemtime is defined in ifwinty.f90 (kernel32):
!     TYPE T_SYSTEMTIME
!     SEQUENCE
!       integer(WORD) wYear ! knowns  WORD 
!       integer(WORD) wMonth ! knowns  WORD 
!       integer(WORD) wDayOfWeek ! knowns  WORD 
!       integer(WORD) wDay ! knowns  WORD 
!       integer(WORD) wHour ! knowns  WORD 
!       integer(WORD) wMinute ! knowns  WORD 
!       integer(WORD) wSecond ! knowns  WORD 
!       integer(WORD) wMilliseconds ! knowns  WORD 
!     END TYPE
    
    Integer(T_Time):: i8time
    
    write(*,*) "T_time=0 at ", SystemtimeFromI8Time(0_8)
    write(*,*)
    
    write(*,*) "Local time is:"
    i8time=GetLocaltimeAsI8time()    
    write(*,*) SystemtimeFromI8Time(I8time)
    
    write(*,*)
    Write(*,*) "Add 24h"
    I8time=I8time + 24_8*3600_8*second
    write(*,*) SystemtimeFromI8Time(I8time)
    
    Write(*,*) 'Press enter to close window'
    read(*,*) 
    
    end 

 

0 Kudos
Brian_Murphy
New Contributor II
4,219 Views

Fantastic!  I like this libdate module a lot.  I do not need to handle seconds or milliseconds.  Before I started this thread I searched with Google for fortran date handling routines, and all I found was m_time.  I wish I had found libdate.

0 Kudos
Brian_Murphy
New Contributor II
4,219 Views

Thank you, LeonardB.  That gives me two good options.

0 Kudos
dboggs
New Contributor I
4,219 Views

Thanks to all for these contributions.

A permanent entry on my wish list for Fortran is a new data type, Dattime (or whatever). Like some other languages (especially Excel, to use the term loosely) it would handle not only arithmetic, but some functions (e.g. Julian date conversion) and a family of edit descriptors for I/o. Would save lots of people lots of time.

0 Kudos
Steve_Lionel
Honored Contributor III
4,219 Views

Far too many options for an intrinsic data type. It's straightforward to define a derived type and supply a library for something like this. Formatting, in particular, is especially complex and varied.

0 Kudos
Brian_Murphy
New Contributor II
3,909 Views

Makes you appreciate the work that went into the VBA features for handling dates and times.  Save folks a lot of extra work.

0 Kudos
Reply