DateTime Format Weirdness

canalrun

Well-Known Member
Licensed User
Longtime User
Hello,
I would like to format my Date output to use two digit years and format the Time output to remove the seconds.

I can't set the DateTime.Dateformat and DateTime.Timeformat variables statically (especially the date) because of localization differences – mm/dd/yyyy vs yyyy/mm/dd ...

In my Activity_Resume I create a global string variable with "yyyy" replaced by "yy". I display the original dateformat and my new variable in a Log statement. Everything looks good.

DateFormat MM/dd/yyyy
MyDatFmt MM/d/yy
TimeFormat HH:mm:ss
MyTimFmt HH:mm

Later in my code in response to a button click I set dateformat to my variable.

As soon as I put in that line of code, dateformat in my Activity_Resume Log statement changes to the empty string. (Note this happens long before my statement in the button click is actually executed).

DateFormat
MyDatFmt
TimeFormat
MyTimFmt

If instead in my button click, I change dateformat statically to the string "mm/dd/yy" all is fine and my Activity_Resume Log statement reflects the new dateformat value – even before the static assignment is executed in the button click.

It looks like something is intercepting the fact that I may want to change the dateformat at some point and making the change very early in my apps execution. If I eventually set dateformat to a variable, early in my apps execution the variable is empty so dateformat becomes empty. If I eventually set dateformat to a static string, "mm/dd/yy", it is set to this early in my programs execution and that value is reflected in the Activity_Resume Log statement.

Could this be true?

In Delphi there is a statement: FormatDateTime. This allows you to provide a format string and a DateTime value. It produces string output according to the format string. Is there something like this in B4A? How do I custom format DateTime output?

Thanks,
Barry.
 

edgar_ortiz

Active Member
Licensed User
Longtime User
I hope that this will usefull to you.

B4X:
Sub Get_Format_Date (ParFecha As Long, ParFormato As String)
   Dim lcResultado As String
   lcResultado   = ""
   '
   Select ParFormato 
      Case "YYYYMMDD"
         lcResultado   = NumberFormat2(DateTime.GetYear(ParFecha),4,0,0,False) & _
                     NumberFormat2(DateTime.GetMonth(ParFecha),2,0,0,False) & _
                     NumberFormat2(DateTime.GetDayOfMonth(ParFecha),2,0,0,False)
      Case "YYYYMMDD HHMMSS"
         lcResultado   = NumberFormat2(DateTime.GetYear(ParFecha),4,0,0,False) & _
                     NumberFormat2(DateTime.GetMonth(ParFecha),2,0,0,False) & _
                     NumberFormat2(DateTime.GetDayOfMonth(ParFecha),2,0,0,False) & " " & _
                     NumberFormat2(DateTime.GetHour(ParFecha),2,0,0,False) & _
                     NumberFormat2(DateTime.GetMinute(ParFecha),2,0,0,False) & _
                     NumberFormat2(DateTime.GetSecond(ParFecha),2,0,0,False)
      Case "YYYY-MM-DD HH:MM:SS"
         lcResultado   = NumberFormat2(DateTime.GetYear(ParFecha),4,0,0,False) & "-" & _
                     NumberFormat2(DateTime.GetMonth(ParFecha),2,0,0,False) & "-" & _
                     NumberFormat2(DateTime.GetDayOfMonth(ParFecha),2,0,0,False) & " " & _
                     NumberFormat2(DateTime.GetHour(ParFecha),2,0,0,False) & ":" & _
                     NumberFormat2(DateTime.GetMinute(ParFecha),2,0,0,False) & ":" & _
                     NumberFormat2(DateTime.GetSecond(ParFecha),2,0,0,False)
      Case "DD-MM-YYYY"
         lcResultado   = NumberFormat2(DateTime.GetDayOfMonth(ParFecha),2,0,0,False) & "-" & _
                     NumberFormat2(DateTime.GetMonth(ParFecha),2,0,0,False) & "-" & _
                     NumberFormat2(DateTime.GetYear(ParFecha),4,0,0,False)
      Case "DD-MM-YYYY HH:MM:SS"
         lcResultado   = NumberFormat2(DateTime.GetDayOfMonth(ParFecha),2,0,0,False) & "-" & _
                     NumberFormat2(DateTime.GetMonth(ParFecha),2,0,0,False) & "-" & _
                     NumberFormat2(DateTime.GetYear(ParFecha),4,0,0,False) & " " & _
                     NumberFormat2(DateTime.GetHour(ParFecha),2,0,0,False) & ":" & _
                     NumberFormat2(DateTime.GetMinute(ParFecha),2,0,0,False) & ":" & _
                     NumberFormat2(DateTime.GetSecond(ParFecha),2,0,0,False)
      Case "DD-MM-YYYY HH:MM"
         lcResultado   = NumberFormat2(DateTime.GetDayOfMonth(ParFecha),2,0,0,False) & "-" & _
                     NumberFormat2(DateTime.GetMonth(ParFecha),2,0,0,False) & "-" & _
                     NumberFormat2(DateTime.GetYear(ParFecha),4,0,0,False) & " " & _
                     NumberFormat2(DateTime.GetHour(ParFecha),2,0,0,False) & ":" & _
                     NumberFormat2(DateTime.GetMinute(ParFecha),2,0,0,False)
      Case Else
         lcResultado = ""
         ' Msgbox("Formato de Fecha Invalido", "ERROR")
   End Select
   '
   Return lcResultado
End Sub

Regards,

Edgar Ortiz
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
You can use code like below:
B4X:
    ' define process global variables
    Dim DateFormat, MyDateFormat, TimeFormat, MyTimeFormat As String
    
    
    ' get standard formats
    DateFormat = DateTime.DateFormat
    TimeFormat = DateTime.TimeFormat
    
    
    ' define my formats
    MyDateFormat = "MM/d/yy"
    MyTimeFormat = "HH:mm"
    
    
    ' set my formats
    DateTime.DateFormat = MyDateFormat
    DateTime.TimeFormat = MyTimeFormat
    
    
    ' restore standard formats
    DateTime.DateFormat = DateFormat
    DateTime.TimeFormat = TimeFormat
Best regards.
 
Upvote 0

canalrun

Well-Known Member
Licensed User
Longtime User
You can use code like below:

Thanks. I wrote a little program to test my error. Happily, I was not able to reproduce the error with this little example.

In the test program, block comment out Section A or Section B or both. Run the program in debug mode and look at the log file output. The results are as expected.

B4X:
'Activity module
Sub Process_Globals
End Sub

Sub Globals
  Dim MyDateFormat, MyTimeFormat As String
End Sub

Sub Activity_Create(FirstTime As Boolean)
  Log("1. DateFormat " & DateTime.DateFormat)
  Log("1. MyDateFormat " & MyDateFormat)

  Log("1. TimeFormat " & DateTime.TimeFormat)
  Log("1. MyTimeFormat " & MyTimeFormat)
End Sub

Sub Activity_Resume

'  ' Section A
'  DateTime.DateFormat = "mm/d/yy"
'  DateTime.TimeFormat = "HH:mm"
'  ' End Section A
  
  ' Section B
  MyDateFormat = DateTime.DateFormat
  MyDateFormat = MyDateFormat.Replace("yyyy", "yy")
  DateTime.DateFormat = MyDateFormat
  
  MyTimeFormat = DateTime.TimeFormat
  MyTimeFormat = MyTimeFormat.Replace(":ss", "")
  DateTime.TimeFormat = MyTimeFormat
  ' End Section B

  Log("2. DateFormat " & DateTime.DateFormat)
  Log("2. MyDateFormat " & MyDateFormat)

  Log("2. TimeFormat " & DateTime.TimeFormat)
  Log("2. MyTimeFormat " & MyTimeFormat)
  
End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Thanks,
Barry.
 
Last edited:
Upvote 0

canalrun

Well-Known Member
Licensed User
Longtime User
Thanks edgar_ortiz and klaus.

Here is a FormatDateTime subroutine I wrote that sort of mimics the function available in Delphi. I took a brute force approach. I am sure it could be much more efficient.

This allows you to specify exactly how date and time strings will appear. I've attached a demo project. (Note the demo outputs to the Log not the device.)

One thing I cannot find in Android or B4A is the localized date, time, thousands, decimal separators and YMD standard used by the device.

In the US we use "/" as the date separator. Other locales use ".", "–", or other characters to separate the month, day and year in a date. Time is similar – ":", ".". Thousands and decimal separators are similar, as is the YMD order – ymd, mdy, dmy.

Is there a way to determine these values from the device's local settings?

Thanks,
Barry.


B4X:
' HH - hours, always 2 digit, 24 hour
' H - hours, possibly 1 digit, 24 hour
' hh - hours, always 2 digit, 12 hour
' h - hours, possibly 1 digit, 12 hour
' mm - minutes, always 2 digit
' m - minutes, possibly 1 digit
' ss - seconds, always 2 digits
' yyyy - full year value (4 digits)
' yy - truncated year (2 digits)
' MMM - month three letter abrev.
' MM - month, always 2 digits
' M - month, possibly 1 digit
' dd - day of month, always 2 digits
' d - day of month, possibly 1 digit

Sub FormatDateTime(fmt As String, dt As Long) As String
  Dim i, j As Int
  Dim s, t, so, MonthNames(12) As String
  
  s = fmt
  so = ""
  MonthNames = Array As String("Jan", "Feb", "Mar", "Apr", _
    "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
  
  Do While (s.Length > 0)
    If (s.StartsWith("HH")) Then
     t = NumberFormat2(DateTime.GetHour(dt), 2, 0, 0, False)
     j = 2
   Else If (s.StartsWith("H")) Then
     t = NumberFormat2(DateTime.GetHour(dt), 1, 0, 0, False)
     j = 1
   Else If (s.StartsWith("hh")) Then
     i = DateTime.GetHour(dt)
     If (i > 12) Then i = i - 12
     t = NumberFormat2(i, 2, 0, 0, False)
     j = 2
   Else If (s.StartsWith("h")) Then
     i = DateTime.GetHour(dt)
     If (i > 12) Then i = i - 12
     t = NumberFormat2(i, 1, 0, 0, False)
     j = 1
   Else If (s.StartsWith("mm")) Then
     t = NumberFormat2(DateTime.GetMinute(dt), 2, 0, 0, False)
     j = 2
   Else If (s.StartsWith("m")) Then
     t = NumberFormat2(DateTime.GetMinute(dt), 1, 0, 0, False)
     j = 1
   Else If (s.StartsWith("ss")) Then
     t = NumberFormat2(DateTime.GetSecond(dt), 2, 0, 0, False)
     j = 2
   Else If (s.StartsWith("yyyy")) Then
     t = NumberFormat2(DateTime.GetYear(dt), 1, 0, 0, False)
     j = 4
   Else If (s.StartsWith("yy")) Then
     t = NumberFormat2(DateTime.GetYear(dt), 1, 0, 0, False)
     i = Max(t.Length - 2, 0)
     t = t.SubString(i)
     j = 2
   Else If (s.StartsWith("MMM")) Then
     i = DateTime.GetMonth(dt)
     t = MonthNames(i - 1)
     j = 3
   Else If (s.StartsWith("MM")) Then
     t = NumberFormat2(DateTime.GetMonth(dt), 2, 0, 0, False)
     j = 2
   Else If (s.StartsWith("M")) Then
     t = NumberFormat2(DateTime.GetMonth(dt), 1, 0, 0, False)
     j = 1
   Else If (s.StartsWith("dd")) Then
     t = NumberFormat2(DateTime.GetDayOfMonth(dt), 2, 0, 0, False)
     j = 2
   Else If (s.StartsWith("d")) Then
     t = NumberFormat2(DateTime.GetDayOfMonth(dt), 1, 0, 0, False)
     j = 1
   Else
     t = s.SubString2(0, 1)
     j = 1
   End If
   
   so = so & t
   s = s.SubString(j)
  Loop
  
  Return(so)
End Sub
 

Attachments

  • DTDemo.zip
    6.1 KB · Views: 245
Last edited:
Upvote 0

JakeBullet70

Well-Known Member
Licensed User
Longtime User
Nice code, thanks.

WOW,
Take a look at AHLocale
has all this formatting built in plus lots more.
 
Last edited:
Upvote 0

alan dodd

Member
Licensed User
Longtime User
Hello everybody.
Maybe an already answered question:

If first app executes this:

DateTime.TimeFormat = "HH:mm"
DateTime.DateFormat = "yyyy-MM-dd"

Do these new formats become global for the phone, I mean if I start another new app, does it use the new settings?
And if I close the app that originated the new format, does the format remain changed?
Thank you
A.
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
This is an OLD thread. Start a new one for your question!
 
Upvote 0
Top