B4J Question Smart String Literal

mading1309

Member
Licensed User
Longtime User
I run into a trouble with Smart String Literals and $Datetime
The long number 1546127715000
is converted to 2019.12.30 07:55:15
But the long number 1572393316601
is converted to 2019.10.30 07:55:16
The first number is less than the second and results in a date in the future
Why and where is my problem?
I attach the ZIP file of small program written in B4J Version 7.8
 

Attachments

  • date test.zip
    1.2 KB · Views: 206

LucaMs

Expert
Licensed User
Longtime User
The project you have attached cannot do anything, since the file is not found, of course.

However, doing this test (very similar to your code):
B4X:
DateTime.TimeFormat = "HH:mm:ss"
DateTime.DateFormat = "YYYY.MM.dd "
 
Dim mm As Map
mm.Initialize
Dim l As Long = 1546127715000
mm.Put("1", l)
l = 1572393316601
mm.Put("2", l)
 
File.WriteMap(File.DirApp, "Dates", mm)
mm = File.ReadMap(File.DirApp, "Dates")
 
Log ($"Ticks ${mm.Get("1")} ==> $DateTime{mm.Get("1")}"$)
Log ($"Ticks ${mm.Get("2")} ==> $DateTime{mm.Get("2")}"$)

I get these logs:

Ticks 1546127715000 ==> 2018.12.30 00:55:15
Ticks 1572393316601 ==> 2019.10.30 00:55:16
 
Last edited:
Upvote 0

alwaysbusy

Expert
Licensed User
Longtime User
EDIT: see https://www.b4x.com/android/forum/threads/smart-string-literal.110920/#post-692090 for the solution. It is not a bug.

------------------------
just for info
------------------------
The bug doesn't seem to be limited to smart strings. I got the same wrong results just using datatime.date() but this is probably because internally it uses the same java code.

Seems to be in java itself when a timezone is introduced:
B4X:
   ...
  
   Dim l1 As Long = 1546127715000
   Dim l2 As Long = 1572393316601
 
   Dim NativeMe As JavaObject
   NativeMe = Me
 
   Log("wrong")
   Dim s As String = NativeMe.RunMethod("convertTime", Array(l1))
   Log(s)
   Dim s As String = NativeMe.RunMethod("convertTime", Array(l2))
   Log(s)
 
   Log("wrong")
   Dim s As String = NativeMe.RunMethod("convertTime2", Array(l1))
   Log(s)
   Dim s As String = NativeMe.RunMethod("convertTime2", Array(l2))
   Log(s)
 
   Log("right")
   Dim s As String = NativeMe.RunMethod("convertTime3", Array(l1))
   Log(s)
   Dim s As String = NativeMe.RunMethod("convertTime3", Array(l2))
   Log(s)
 
   'StartMessageLoop
End Sub

#if JAVA
import java.util.Date;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.ZoneOffset;
import java.time.ZoneId;

public static String convertTime(long time){
    Date date = new Date(time);
    SimpleDateFormat format = new SimpleDateFormat("YYYY.MM.dd HH:mm:ss");
    return format.format(date);
}

public static String convertTime2(long millisecondsSinceEpoch) {
   Instant instant = Instant.ofEpochMilli ( millisecondsSinceEpoch );
   ZoneId systemZone = ZoneId.systemDefault();
   ZoneOffset currentOffsetForMyZone = systemZone.getRules().getOffset(instant);
   ZonedDateTime zdt = ZonedDateTime.ofInstant ( instant , currentOffsetForMyZone );

   DateTimeFormatter formatter = DateTimeFormatter.ofPattern ("YYYY.MM.dd HH:mm:ss" );
   return formatter.format ( zdt );
}

public static String convertTime3(long millisecondsSinceEpoch) {
   Instant instant = Instant.ofEpochMilli ( millisecondsSinceEpoch );
   ZonedDateTime zdt = ZonedDateTime.ofInstant ( instant , ZoneOffset.UTC );

   DateTimeFormatter formatter = DateTimeFormatter.ofPattern ("YYYY.MM.dd HH:mm:ss" );
   return formatter.format ( zdt );
}
#End If

result:
B4X:
wrong
2019.12.30 00:55:15
2019.10.30 00:55:16
wrong
2019.12.30 00:55:15
2019.10.30 00:55:16
right (note 2018 instead of 2019 for the first one)
2018.12.29 23:55:15
2019.10.29 23:55:16
 
Last edited:
Upvote 0

mading1309

Member
Licensed User
Longtime User
Hello
Thanks your quick reply LucaMS.
Sorry I did not double check the ZIP file. I expect the file is in DirAPP is included. But you are right it should not be because outside of the project folder.
thanks again your efforts.

I am interested in why these different results and how they can be recognized and be avoided. Is the time zone the only possible reason?
 
Last edited:
Upvote 0

mading1309

Member
Licensed User
Longtime User
Hello
thanks your quick reply alwaysbusy and efforts.

Can "convertTime3" in your example above be a general "go around" for this bug?
if so, I can stay with this solution.
 
Upvote 0

mading1309

Member
Licensed User
Longtime User
Hello Erel
thanks you reply
i attached the ZIP file of source code and the data file "lastaction.t4" (also as zip file) of the DIRData folder
the data file lastaction.t4 holds only 2 value pairs

#Wed Oct 30 14:08:42 CST 2019
lastGPS=1572402259926
lastSMS=1546127805000

and results in (log screen)

version 2019 10 30
application folder D:\Projekts\BAJ\T4\Objects
data folder C:\Users\Wode\AppData\Roaming\class b4j.example.main
Last valid SMS 1546127805000 ==> 2019.12.30 07:56:45
Last valid GPS 1572402259926 ==> 2019.10.30 10:24:19

Thanks your efforts
 

Attachments

  • date test.zip
    1.2 KB · Views: 197
  • Lastaction.zip
    232 bytes · Views: 208
Upvote 0

alwaysbusy

Expert
Licensed User
Longtime User
I didn't notice it, but your date fomatting is wrong:

Using this:
B4X:
DateTime.TimeFormat = "HH:mm:ss"
DateTime.DateFormat = "yyyy.MM.dd" '<---- yyyy instead of YYYY

result (first one is 2018, not 2019):
B4X:
Ticks 1546127715000 ==> 2018.12.30 00:55:15
Ticks 1572393316601 ==> 2019.10.30 00:55:16

So no bug :)
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
There are many mistakes in this example which makes it difficult to even try it.

1. File.DirData(Me) is wrong. You should pass the app name.

2. Put the file in the Files folder and load it from File.DirAssets.

3. Initializing an object before you assign a different object to the variable is a mistake.

4. As @alwaysbusy wrote the format is incorrect (there is also an extra space).
 
Upvote 0

alwaysbusy

Expert
Licensed User
Longtime User
Yes, I noticed YYYY instead of yyyy but the result of my test (#2) does not change.
Sure? Your code does give me the correct dates with yyyy instead of YYYY:

B4X:
Ticks 1546127715000 ==> 2018.12.30  00:55:15 ' <----------- note it is 2018, not 2019 (with YYYY it gives 2019)
Ticks 1572393316601 ==> 2019.10.30  00:55:16
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
upload_2019-10-30_14-42-48.png
 
Upvote 0

mading1309

Member
Licensed User
Longtime User
Hello

thanks to all for their effort

Yes, I did not recognize the Format for the year is wrong. I changed and the problem was solved
The ending space i thought is no problem, I removed now

@Erel
If I use File.DirAssets then the file location is read only, right? This was the reason I had chosen File.DirData
Thanks for the hint of wrong use of File.DirData parameter.
I removed to initialize of Lastaction. Does my mistake results in 2 objects?
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
Sure? Your code does give me the correct dates with yyyy instead of YYYY:
Since @alwaysbusy comment still raises some doubts in me :D, I tried again:
B4X:
   DateTime.TimeFormat = "HH:mm:ss"
   DateTime.DateFormat = "YYYY.MM.dd"
   Log("YYYY.MM.dd")
   Log ($"Ticks ${mm.Get("1")} ==> $DateTime{mm.Get("1")}"$)
   Log ($"Ticks ${mm.Get("2")} ==> $DateTime{mm.Get("2")}"$)
   DateTime.DateFormat = "yyyy.MM.dd"
   Log("yyyy.MM.dd")
   Log ($"Ticks ${mm.Get("1")} ==> $DateTime{mm.Get("1")}"$)
   Log ($"Ticks ${mm.Get("2")} ==> $DateTime{mm.Get("2")}"$)

And the log:

YYYY.MM.dd
Ticks 1546127715000 ==> 2018.12.30 00:55:15
Ticks 1572393316601 ==> 2019.10.30 00:55:16
yyyy.MM.dd
Ticks 1546127715000 ==> 2018.12.30 00:55:15
Ticks 1572393316601 ==> 2019.10.30 00:55:16


So I'm not so sure that...
Yes, I did not recognize the Format for the year is wrong. I changed and the problem was solved
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
3. Initializing an object before you assign a different object to the variable is a mistake.
I removed to initialize of Lastaction. Does my mistake results in 2 objects?
This code?
B4X:
Lastaction.Initialize
Lastaction = File.ReadMap (File.DirData(Me),"Lastaction.t4")

I think that in this case you don't need to inizialize the map, but you can, without any problem.
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
I think that in this case you don't need to inizialize the map, but you can, without any problem.
Tested anyway and...
B4X:
Sub AppStart (Args() As String)
    Dim m As Map
    m.Initialize
    m.Put(1,1)
    File.WriteMap(File.DirApp, "m", m)

    Private mapX As Map
'    mapX.Initialize
    mapX = File.ReadMap(File.DirApp, "m")
    Log(mapX.Get(1))
End Sub

With or without the initialization the log I get is...
null !

It's time for me to retire!


P.S. I have to use a string value as key (map), this way it works :eek: (event without initializing mapX, as "supposed")
 
Last edited:
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
If I use File.DirAssets then the file location is read only, right?
True. But when you upload a project you should make it easier for the other developers to test it.

I removed to initialize of Lastaction. Does my mistake results in 2 objects?
Yes, though it will not really hurt the performance. It is more of a "bad design".

Best way:
B4X:
Dim mapX As Map = File.ReadMap(...)
 
Upvote 0
Top