Android Tutorial [B4X] DateUtils - Simplifies Date and Time Calcuations

DateUtils is a code module with a set of useful date and time related methods.
It complements DateTime api, it doesn't replace it.

The methods included in DateUtils:

B4X:
'Calculates the period between two date instances.
'This method returns a Period type with years, months, days, hours, minutes, seconds.
Sub PeriodBetween(Start As Long, EndTime As Long) As Period

'Calculates the period between two date instances.
'This method returns a Period type with days, hours, minutes, seconds
Sub PeriodBetweenInDays (Start As Long, EndTime As Long) As Period

'Returns the month name of the given date.
'Similar To DateTime.GetMonth which returns the month as an integer.
Sub GetMonthName(Ticks As Long) As String

'Returns the day of week name.
'Similar to DateTime.GetDayOfWeek which returns the day of week as an integer.
Sub GetDayOfWeekName(Ticks As Long) As String

'Returns a list with the week days names, using the device set locale.
Sub GetDaysNames As List

'Returns a list with the months names, using the device set locale.
Sub GetMonthsNames As List

'Returns the ticks value of the given date (the time will be 00:00:00).
Sub SetDate(Years As Int, Months As Int, Days As Int) As Long

'Returns the ticks value of the given date and time
Sub SetDateAndTime(Years As Int, Months As Int, Days As Int, Hours As Int, Minutes As Int, Seconds As Int) As Long

'Returns the ticks value of the given date and time with the specified time zone offset.
'The last parameter is the time zone offset measured in hours.
Public Sub SetDateAndTime2(Years As Int, Months As Int, Days As Int, Hours As Int, Minutes As Int, Seconds As Int, _
      TimeZone As Double) As Long

'Returns the number of days in the given month
Sub NumberOfDaysInMonth(Month As Int, Year As Int) As Int

'Adds a Period to the given date instance. Do not forget to assign the result.
Sub AddPeriod(Ticks As Long, Per As Period) As Long

'Tests whether the two ticks values represent the same day.
Sub IsSameDay(Ticks1 As Long, Ticks2 As Long) As Boolean

'Converts ticks value to unix time.
Sub TicksToUnixTime(Ticks As Long) As Long

'Converts unix time to ticks value.
Sub UnixTimeToTicks(UnixTime As Long) As Long

DateUtils includes a type named Period:
B4X:
Type Period (Years As Int, Months As Int, _
      Days As Int, Hours As Int, Minutes As Int, Seconds As Int)

You can use PeriodBetween method to get the Period between two dates.
AddPeriod method adds a Period to a given date instance.

The DateUtils module is included in the attached example.

v1.05: Adds SetDateAndTime2. Allows you to explicitly set the time zone.

v1.03: Fixes a bug in NumberOfDaysInMonth method.

v1.02: Fixes a locale related bug (SetDate and SetDateAndTime).

v1.01: Adds PeriodBetweenInDays - Similar to PeriodBetween however the years and months will be zero (days field will be larger as needed).
This version also fixes a bug in SetDateAndTime related to DST

Starting from B4A v2.70, DateUtils is included as a library in the IDE.
 
Last edited:

BPak

Active Member
Licensed User
Longtime User
I use Days between two dates in a lot of my apps.

B4X:
' Get the days difference between two dates...
   
' y - m - d - Most recent date
Dim newDate As Long = DateUtils.SetDate(2013, 2, 2)

' y - m - d - Earlier date
Dim oldDate As Long = DateUtils.SetDate(2013, 1, 19)

' = 14 days difference
Dim daysDiff As Int = DateUtils.DaysBetween(oldDate, newDate)

Log(daysDiff)

:sign0142:
 

BPak

Active Member
Licensed User
Longtime User
I have to have it in DAYS as it is used to calculate values in the program.

Thank you.
 

gregwa

Member
Licensed User
Longtime User
BPak,

You can do it this way...

Assume a "start" date of Jan 1 2012
Assume an "end" date of Dec 31 2012
Tics for start date would come out to 1325401200000
Tics for end date would come out to 1356937200000
There are 86400000 ticks per day (DateTime.TicsPerDay)
If you subtract end date ticks from start date you get 31536000000
Divide Tick Difference by ticks per day, you get 365 days

startdate = 7/18/1953
enddate = 2/15/2013
should come up to 21,762 days not including 2/15/2013 (add one if you want that)

Using your example code above...


B4X:
Dim newdate As Long = dateutils.SetDate(2013,2,15)
   ' y - m - d - Earlier date
   Dim olddate As Long = dateutils.SetDate(1953,7,18)

   Log("Ticks for newDate = " & newdate)
   Log("Ticks for OldDate = " & olddate)
   Log("ticks per day = " & DateTime.ticksperday)
   Log("Diff between old and new date in ticks = " & (newdate-olddate))
   
   Dim dayspast As Int
   dayspast = (newdate-olddate)/ DateTime.TicksPerDay
   Log(dayspast)

So a quick sub would be:

B4X:
Sub DaysOut(startyear, startmonth, startday, endyear, endmonth, endday As Int, IncludeEndDay As Boolean) As Int
   Dim newdate As Long
   Dim olddate As Long
   Dim dayspast As Int
   '============================
   newdate = DateUtils.SetDate(startyear,startmonth,startday)
   olddate = DateUtils.SetDate(endyear,endmonth,endday)
   dayspast = (newdate-olddate)/ DateTime.TicksPerDay
   If IncludeEndDay = True Then
      If dayspast < 0 Then
         Return dayspast - 1
      Else
         Return dayspast + 1
      End If
   Else
      Return dayspast
   End If
End Sub

and your example calls would be...
B4X:
   Log("Return from DaysOut is " & DaysOut(2013,2,15,1953,7,18,False)) ' 21762
   Log("Return from second call is " & DaysOut(1953,7,18,2013,2,15,False)) '-21762
   Log("Return from third is " & DaysOut(2013,2,15,1953,7,18,True)) ' 21763
   Log("Return from final call is " & DaysOut(1953,7,18,2013,2,15,True)) '-21763
 
Last edited:

IanMc

Well-Known Member
Licensed User
Longtime User
Wow! Thanks Erel!

:sign0142:

Looky here:

new Sub Activity_Create(FirstTime As Boolean)
B4X:
Sub Activity_Create(FirstTime As Boolean)
   ToastMessageShow("Check the logs...", True)
   Log("Today is " & DateUtils.GetDayOfWeekName(DateTime.Now))
   Log("There are " & DateUtils.NumberOfDaysInMonth(DateTime.GetMonth(DateTime.Now), _
      DateTime.GetYear(DateTime.Now)) & " days in this month.")
   Dim targetDate As Long = DateUtils.SetDate(2014, 1, 1)
   Dim timeToDate As Period = DateUtils.PeriodBetween(DateTime.Now, targetDate)
   Log(timeToDate)
   Log("Time left to 2014: " & timeToDate.Months & " months, " & timeToDate.Days & " days")
   
'Ian Code
   ' y - m - d - Target date
   Dim expiryDate As Long = DateUtils.SetDate(2013, 3, 14) 'I want the expiry date for this app to be halfway through March
   Dim betweenNowAndThen As Period = DateUtils.PeriodBetween(DateTime.Now, expiryDate)
   Log(" ")
   Log("Have fun with this app but know that it will expire at " & ampmTime(expiryDate) & " on " & DateUtils.GetDayOfWeekName(expiryDate) & _ 
   " the " & daySuffix(DateTime.GetDayOfMonth(expiryDate)) & " of " & DateUtils.GetMonthName(expiryDate) & ", " & DateTime.GetYear(expiryDate))

   Log("Although you can cheat and keep on using it if you are willing to set the Android device time to any date/time before this one.")
   Log("But only loo, hooo, hoooosers would do that :)")
   Log(" ")
   Log("Now Int = " & DateTime.Now)
   Log("expiryDate Int = " & expiryDate)
   Log("Period Between Now and expiryDate = " & betweenNowAndThen)
   Log(" ")

   If DateTime.Now >= expiryDate Then
      Log("Time's up suckers!")
      Log("Show Sorry, this app has expired Activity")
      Log("Quit app")
      Log(" ")
   Else
      Log("You have " & betweenNowAndThen.Days & " days of your trial period left!")
      Log(" ")   
   End If   
End Sub
and IanCode:
B4X:
Sub ampmTime(dt As Long) As String
        Dim h As Int
    Dim i As Double
        i = DateTime.GetMinute(dt)
        h = DateTime.GetHour(dt)
        If h <= 11 Then
                If h = 0 Then h = 12 'coz we can't have hours as zero :)
                Return h & ":" & NumberFormat(i, 2, 0) & "am"
        End If
        h = h - 12
        If h = 0 Then h = 12 'coz we can't have hours as zero :)
        Return h & ":" & NumberFormat(i, 2, 0) & "pm"
End Sub

Sub daySuffix(i As Int) As String 'add suffix to integer such as 10th 3rd 1st 2022nd etc.
        Dim s As String
        Dim j As Int
        s = i 'change the int to a string
        j = i 'make a copy of i that we can chop up
        If s.Length > 2 Then s = s.SubString(s.Length - 2)
        j = s 'j is now a number that is no bigger than 2 digits
        If j >= 4 AND j <= 20 Then Return i & "th" 'these last few
        If s.EndsWith("1") Then Return i & "st"    'lines work out
        If s.EndsWith("2") Then Return i & "nd"    'the correct suffix
        If s.EndsWith("3") Then Return i & "rd"    'and send back the
        Return i & "th" 'original number as a string with the correct suffix after it.
End Sub

:sign0087:
 

IanMc

Well-Known Member
Licensed User
Longtime User
oh darn

Oh :signOops:

If I increase the expiry date by one month:

Dim expiryDate As Long = DateUtils.SetDate(2013, 4, 14)

It tells me I have 20 days left .... hmmmm... what am I doing wrong here?
 

IanMc

Well-Known Member
Licensed User
Longtime User
Still not resolved.

Can anyone spot the error?
B4X:
Sub Activity_Create(FirstTime As Boolean)
   ToastMessageShow("Check the logs...", True)
   Log("Today is " & DateUtils.GetDayOfWeekName(DateTime.Now))
   Log("There are " & DateUtils.NumberOfDaysInMonth(DateTime.GetMonth(DateTime.Now), _
      DateTime.GetYear(DateTime.Now)) & " days in this month.")
   Dim targetDate As Long = DateUtils.SetDate(2014, 1, 1)
   Dim timeToDate As Period = DateUtils.PeriodBetween(DateTime.Now, targetDate)
   Log(timeToDate)
   Log("Time left to 2014: " & timeToDate.Months & " months, " & timeToDate.Days & " days")
   Log(" ")
   Log(" ")
   
'Ian Code
   ' y - m - d - Target date
   Dim expiryDate As Long = DateUtils.SetDate(2013, 4, 14) 'I want the expiry date for this app to be halfway through April
   Dim betweenNowAndThen As Period = DateUtils.PeriodBetween(DateTime.Now, expiryDate)
   Log(" ")
   Log("According to this code, the number of days between now ") 

   Log(DateUtils.GetDayOfWeekName(DateTime.Now) & " the " & daySuffix(DateTime.GetDayOfMonth(DateTime.Now)) & " of " & _
   DateUtils.GetMonthName(DateTime.Now) & ", " & DateTime.GetYear(DateTime.Now))
   Log("and my expiry date:")

   Log(DateUtils.GetDayOfWeekName(expiryDate) & " the " & daySuffix(DateTime.GetDayOfMonth(expiryDate)) & " of " & _
   DateUtils.GetMonthName(expiryDate) & ", " & DateTime.GetYear(expiryDate))
   Log("is " & betweenNowAndThen.Days)
   Log("???? huh? .... we have the whole month of March before April, what about those 31 days?")
      
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub daySuffix(i As Int) As String 'add suffix to integer such as 10th 3rd 1st 2022nd etc.
        Dim s As String
        Dim j As Int
        s = i 'change the int to a string
        j = i 'make a copy of i that we can chop up
        If s.Length > 2 Then s = s.SubString(s.Length - 2)
        j = s 'j is now a number that is no bigger than 2 digits
        If j >= 4 AND j <= 20 Then Return i & "th" 'these last few
        If s.EndsWith("1") Then Return i & "st"    'lines work out
        If s.EndsWith("2") Then Return i & "nd"    'the correct suffix
        If s.EndsWith("3") Then Return i & "rd"    'and send back the
        Return i & "th" 'original number as a string with the correct suffix after it.
End Sub

My part of the code prints out:

According to this code, the number of days between now
Monday the 25th of February, 2013
and my expiry date:
Sunday the 14th of April, 2013
is 19
???? huh? .... we have the whole month of March before April, what about those 31 days?

Can anyone see what I'm doing wrong here?
 

IanMc

Well-Known Member
Licensed User
Longtime User
Ah.... so we have to check the value of betweenNowAndThen.Months and add the number of days to that then?

I think it will be a much used function because of 90 day trials etc.

So to get the number of days I will first have to figure out if there are one or more months, and then if there are I will have to then figure out which months these are and then I will need to use DateUtils.NumberOfDaysInMonth to figure out how many days are in each of these months? Oh boy :)

Or is there something I'm missing?

Is there an easy way to use this to find out how many days there are between any two dates?
 

IanMc

Well-Known Member
Licensed User
Longtime User
Yes I'm just having a look at gregwa's code now.

Thanks gregwa!

and of course Thanks Erel!
 

IanMc

Well-Known Member
Licensed User
Longtime User
Yoohooo! Success!

so, we have:
B4X:
Sub Activity_Create(FirstTime As Boolean)
   ToastMessageShow("Check the logs...", True)
   Log("Today is " & DateUtils.GetDayOfWeekName(DateTime.Now))
   Log("There are " & DateUtils.NumberOfDaysInMonth(DateTime.GetMonth(DateTime.Now), _
      DateTime.GetYear(DateTime.Now)) & " days in this month.")
   Dim targetDate As Long = DateUtils.SetDate(2014, 1, 1)
   Dim timeToDate As Period = DateUtils.PeriodBetween(DateTime.Now, targetDate)
   Log(timeToDate)
   Log("Time left to 2014: " & timeToDate.Months & " months, " & timeToDate.Days & " days")
   Log(" ")
   Log(" ")
   
'Ian Code
   ' y - m - d - Target date
   Dim expiryDate As Long = DateUtils.SetDate(2013, 4, 14) 'I want the expiry date for this app to be halfway through March
   Dim betweenNowAndThen As Period = DateUtils.PeriodBetween(DateTime.Now, expiryDate)
   Log(" ")
   Log("According to this code, the number of days between now ") 

   Log(DateUtils.GetDayOfWeekName(DateTime.Now) & " the " & daySuffix(DateTime.GetDayOfMonth(DateTime.Now)) & " of " & _
   DateUtils.GetMonthName(DateTime.Now) & ", " & DateTime.GetYear(DateTime.Now))
   Log("and my expiry date:")

   Log(DateUtils.GetDayOfWeekName(expiryDate) & " the " & daySuffix(DateTime.GetDayOfMonth(expiryDate)) & " of " & _
   DateUtils.GetMonthName(expiryDate) & ", " & DateTime.GetYear(expiryDate))
   Log("is " & DaysBetween(DateTime.Now, expiryDate, True))
   Log("Alrighty then!!! Thanks gregwa!!!")
      
End Sub

and these:
B4X:
Sub daySuffix(i As Int) As String 'add suffix to integer such as 10th 3rd 1st 2022nd etc.
        Dim s As String
        Dim j As Int
        s = i 'change the int to a string
        j = i 'make a copy of i that we can chop up
        If s.Length > 2 Then s = s.SubString(s.Length - 2)
        j = s 'j is now a number that is no bigger than 2 digits
        If j >= 4 AND j <= 20 Then Return i & "th" 'these last few
        If s.EndsWith("1") Then Return i & "st"    'lines work out
        If s.EndsWith("2") Then Return i & "nd"    'the correct suffix
        If s.EndsWith("3") Then Return i & "rd"    'and send back the
        Return i & "th" 'original number as a string with the correct suffix after it.
End Sub

Sub DaysOut(startyear, startmonth, startday, endyear, endmonth, endday As Int, IncludeEndDay As Boolean) As Int
   Dim newdate As Long    
   Dim olddate As Long    
   Dim dayspast As Int    
   '============================    
   newdate = DateUtils.SetDate(startyear,startmonth,startday)    
   olddate = DateUtils.SetDate(endyear,endmonth,endday)    
   dayspast = (newdate-olddate)/ DateTime.TicksPerDay   'I think you need to switch newdate & olddate around here. 
   If IncludeEndDay = True Then                         'so that you subtract newdate from olddate ?
      If dayspast < 0 Then            
         Return dayspast - 1        
            Else            
         Return dayspast + 1        
      End If    
   Else        
      Return dayspast    
   End If
End Sub

Sub DaysBetween(startDate, endDate As Long, IncludeEndDay As Boolean) As Int 'gregwa's code just using Longs 
   Dim dayspast As Int    
   '============================    
   dayspast = (endDate-startDate) / DateTime.TicksPerDay    
   If IncludeEndDay = True Then
      If dayspast < 0 Then            
         Return dayspast - 1        
      Else            
         Return dayspast + 1        
      End If    
   Else        
      Return dayspast    
   End If
End Sub
which giveth this:
** Activity (main) Create, isFirst = true **


Today is Monday


There are 28 days in this month.
[Days=6, Hours=6, IsInitialized=true
, Minutes=21, Months=10, Seconds=40
, Years=0]
Time left to 2014: 10 months, 6 days



According to this code, the number of days between now
Monday the 25th of February, 2013
and my expiry date:
Sunday the 14th of April, 2013
is 48
Alrighty then!!! Thanks gregwa!!!
** Activity (main) Resume **

However, the website http://http://www.timeanddate.com/ begs to differ a little bit in that this part of it: Do the same calculation reckons its 'not' including the last day.... and it must be right coz its on the internet :) .... but this is close enough!
 
Last edited:

gregwa

Member
Licensed User
Longtime User
Thanks Erel! :sign0060:
 

kostas3001

Member
Licensed User
Longtime User
Hi Erel

When I use the emulator, all is OK, but when I use my phone (Sony Experia Neo V, Android 2.3.4), there is an error in SetDateAndTime:[ Return "invalid date" + 1 'hack to throw an error]


Data entry:

targetDate: 24/01/1954 (dd/mm/yy)
fechaDate: 18/03/2013 (dd/mm/yy)

My Code:
---------------------------------------------------------------------------
Sub Process_Globals

End Sub

Sub Globals

Dim dias As Long
Dim nac_anio As EditText
Dim nac_mes As EditText
Dim nac_dia As EditText
Dim fecha_anio As EditText
Dim fecha_mes As EditText
Dim fecha_dia As EditText

Dim targetDate As Long
Dim fechaDate As Long
Dim x As Int

Dim timeToDate As Period

End Sub

Sub Activity_Create(FirstTime As Boolean)

Activity.LoadLayout("prueba2")

fecha_dia.Text=DateTime.GetDayOfMonth(DateTime.Now)
fecha_mes.Text=DateTime.GetMonth(DateTime.Now)
fecha_anio.Text=DateTime.GetYear(DateTime.Now)

End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub Calcular_Click

ToastMessageShow("Check the logs...", True)

targetDate = DateUtils.SetDate(nac_anio.Text, nac_mes.Text, nac_dia.Text)
fechaDate = DateUtils.SetDate(fecha_anio.Text, fecha_mes.Text, fecha_dia.Text)

timeToDate = DateUtils.PeriodBetweenInDays(targetDate, fechaDate)

dias=timeToDate.Days

End Sub
--------------------------------------------------------------------
 

kostas3001

Member
Licensed User
Longtime User
Hi Erel

With [MENU] [Select language] = English, all works fine, but with Spanish language, neither the mobile phone nor the emulator are working...

There is a problem with the library.
 
Top