I want to show the data I have stored in Firebase Realtime Database by filtering according to the date of the users. My data in the database always works according to GMT+3 timezone. But if my user’s time is different from GMT+3, the query will not work correctly. I need some information and code for this. Does anyone have any idea how I can do it?
I store my data as unixtime in the database. For example: 1621717200
startData = FirebaseDatabase.getInstance().getReference() .child("totals") .child(moTracks); PeriodHow = startData.orderByChild("availableDate").startAt(1621717200).endAt(1621803599); PeriodHow.addListenerForSingleValueEvent(new ValueEventListener() { } }
Regards.
Advertisement
Answer
tl;dr
LocalDate .of( 2021 , Month.SEPTEMBER , 26 ) .atStartOfDay( ZoneId.of( "Africa/Tunis" ) ) .toInstant() .getEpochSecond()
To complete your query, do the same but add a day by calling LocalDate#plusDays( 1 )
for the first moment of the next day.
Details
I do not know Firebase. But I can show you how to get a count of seconds since epoch reference.
Of the couple dozen commonly used epoch references, I assume your Firebase tooling is using the first moment of 1970 as seen in UTC (an offset of zero hours-minutes-seconds).
Get the current moment as a count of whole seconds since 1970-01-01T00:00Z. We use Instant
to represent a moment as seen in UTC.
long secondsSinceEpoch = Instant.now().getEpochSecond() ;
Apparently you want to represent an entire day using counts of whole seconds since epoch, but track the day as seen in a particular time zone. Be aware that for any given moment, the date varies around the globe by time zone. It can be “tomorrow” in Tokyo Japan while still “yesterday” in Toledo Ohio US.
ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
You may choose to use the JVM’s current default time zone.
ZoneId z = ZoneId.systemDefault() ;
And furthermore, politicians frequently alter the rules of a time zone, creating anomalies such as days that run longer or shorter than 24 hours, and days that do not start at 00:00. So we let java.time determine the first moment of the day by calling LocalDate#atStartOfDay
.
LocalDate ld = LocalDate.of( 2021 , Month.SEPTEMBER , 26 ) ; ZonedDateTime zdtStart = ld.atStartOfDay( z ) ;
Adjust that moment from the specific time zone to UTC by extracting a Instant
object from our ZonedDateTime
object. We have the same moment, the same point on the timeline, but we perceive a different wall-clock time.
Instant instantStart = zdtStart.toInstant() ;
From the Instant
we get a count of whole seconds since the epoch reference. Beware of data loss: any fractional second on the Instant
is ignored, of course.
long start = instantStart.getEpochSecond() ;
For the beginning of the day, we use the Half-Open approach where the beginning of the day is inclusive while the ending exclusive. So a day starts with the first moment of the day and runs up to, but does not include, the first moment of the next day. This avoids the problem of determining the infinitely divisible last moment.
LocalDate nextDay = ld.plusDays( 1 ) ; ZonedDateTime zdtEnd = nextDay.atStartOfDay( z ) ;
Calculate time elapsed, the length of a day on that date in that zone.
Duration d = Duration.between( zdtStart , zdtEnd ) ; // 23 hours, not 24, for Daylight Saving Time (DST) cut-over on that date in that zone.
Adjust to UTC (an offset of zero). Extract a count of whole seconds since epoch reference.
Instant instantEnd = zdtEnd.toInstant() ; long end = instantEnd.getEpochSecond() ;
Now you can perform your query using start
and end
. Be sure your query is framed as Half-Open. Do not use the SQL command BETWEEN
. Criteria should be using logic of “not before the start AND before the end”.
SELECT * FROM some_table_ WHERE when_ !< ? AND when_ < ? ;
… while using start
and end
longs as the values to plug into those placeholders.
By the way, if your database offers date-time data types, your should be using those as the type of your table columns rather than using mere integers.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes. Hibernate 5 & JPA 2.2 support java.time.
Where to obtain the java.time classes?
- Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later – Part of the standard Java API with a bundled implementation.
- Java 9 brought some minor features and fixes.
- Java SE 6 and Java SE 7
- Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
- Later versions of Android (26+) bundle implementations of the java.time classes.
- For earlier Android (<26), the process of API desugaring brings a subset of the java.time functionality not originally built into Android.
- If the desugaring does not offer what you need, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above) to Android. See How to use ThreeTenABP….