How to modify realm result data when dealing with date and time? ASCENDING and DESCENDING is not enough for me.
Say for example I am getting a task thats within an hour of due?
RealmResults<Task> tmp = realm.where(Task.class).findAll();
for (final Task task : tmp) {
String dateFormat = Utility.TIMEFORMAT;
String current = "2:30:00 PM";
Date currentTime = new Date(task.gettime());
//currentTime = new SimpleDateFormat(dateFormat).parse(current);
if( isIncomingWithInHour(currentTime, calendar)){
realmresult.add(tmp) /// this result in error.
}
}
As you can see ASCENDING and DESCENDING wont work in this kind of sorting. Anyway to give the reamlResult back to the adapter? Realmresult has an onchangeListener and I want to use that.
Instead of
RealmResults<Task> tmp = realm.where(Task.class).findAll();
You can do something like
RealmResults<Task> tasksInOneHour = realm.where(Task.class)
.greaterThanOrEqualTo("time", startTime)
.lowerThan("time", endTime)
.findAll();
Time constraints - while it is not clear in field of which type you store time in your Task class i'll provide an answer for a long field (and if it's not long, i suggest you to use it). Realm has a nice query picking capabilities, which we can make a use of:
RealmResults <Task> tasksInOneHourList =
realm.where(Task.class).between("TIME_LONG_FIELD_NAME", CURRENT_TIME, CURRENT_TIME + HOUR_IN_MILLIS).findAll();
Notify adapter - you can update adapter data as the following:
tasksInOneHourList.addChangeListener(new RealmChangeListener<RealmResults<Task>>() {
#Override
public void onChange(RealmResults<Task> tasks) {
adapter.notifyDataSetChanged();
}
});
Related
I am building a list in flutter and need to sort it by date by showing the most recent timestamp first.
The list is created from a json like the one below:
[
{
"id":100,
"timestamp":"2021-02-02T15:15:11Z",
"name":"Entry1"
},
{
"id":101,
"timestamp":"2021-03-02T11:12:56Z",
"name":"Entry2"
}
]
Once the json is fetched with the fetchEntries function, I'd like to sort the list. This is my code:
class Values extends Object {
int id;
String timestamp;
String name;
Values(
{this.id,
this.timestamp,
this.name});
Values.fromJson(Map<String, dynamic> json) {
id = json["id"];
timestamp = json["timestamp"];
name = json["name"];
}
}
List<Values> _myList = [];
fetchReport() {
_timer = new Timer.periodic(Duration(seconds: 1), (timer) {
fetchEntries(dates.id.toString(), dates.from, dates.to)
.then((value) => {
_myList.addAll(value),
_postsController.add(1),
setState(() {})
});
_timer.cancel();
});
//This is the sort code that doesn't work
_myList.sort((a,b)=> a.timestamp.compareTo(b.timestamp));
}
Alternatively, the list can be sorted by id in decreasing order but the timestamp method is preferred. Any suggestions how to do it properly?
It is better to parse time after fetch data.
_myList.sort((a,b) {
DateFormat formatter = DateFormat("yyyy-MM-ddTHH:mm:ssZ");
DateTime aTime = formatter.parse(a["timestamp"]);
DateTime bTime = formatter.parse(b["timestamp"]);
return aTime.compareTo(bTime);
//return bTime.compareTo(aTime);
}
I think that issue why sorting does not work is that _myList.sort function is called before _myList is filled with data. The reason of that is that _myList is populated in future (when callback of fetchEntires(...).then) is called, while sort function is called right after timer is created (after Timer.periodic constructor).
In order to fix that you need to move _myList.sort to callback just after list is populated with data.
Regarding sorting itself.. While it should work comparing date in the format of your example, I would rather parse time to milliseconds and then compare those instead. Reason is that once you change date format to different one, like 'dd-MM-yyyy' sorting will be broken.
I got a list of objects. I need to go through the list and for each item, I need to set unique timestamp value. How I can implement it?
Now if I understand right the computation makes in less than 1ms so in logs I see weird values.
Here is an example of the code.
List<String> list = new ArrayList<>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
list.add("six");
list.add("seven");
list.add("eight");
list.add("nine");
list.add("ten");
for (String s : list) {
Long tsLong = System.currentTimeMillis() / 1000;
String ts = tsLong.toString();
Log.d("timestamp", s + ts);
}
Logs instead of 10 values it shows 2 equal values
D/timestamp: 1584554340
D/timestamp: 1584554340
Since the iteration goes very fast. I decided to get a timestamp in the beginning of iteration and just make +1 with each loop.
List<String> list = new ArrayList<>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
list.add("six");
list.add("seven");
list.add("eight");
list.add("nine");
list.add("ten");
Long tsLong = System.currentTimeMillis() / 1000;
for (String s : list) {
Log.d("timestamp", tsLong.toString());
tsLong++;
}
In this case, each item got a unique timestamp. That implementation was needed to fill EXISTING db with objects who does not have timestamp value but need to have for present usage. So with help of that I will add unique timestamp to each user which i have in DB.
What I try to accomplish is the following: I have a collection where documents get added with a timestamp in them. I then want to listen to that collection via snapshotlistener, but just for new documents. So I update my timestamp to the newest document-timestamp received, and try to query only the documents newer than my timestamp. In onCreate I assign lastUpdateTime a date in the past, so that I get the first document added.
val sdf = SimpleDateFormat("dd/MM/yyyy", Locale.US)
try {
lastUpdateTime = sdf.parse("01/01/2000")
} catch (e: ParseException) {
//
}
then I add the snapshotlistener and try to update lastUpdateTime in order to just look for documents newer than thist Date/Time
val path = //...path to my collection
private var lastUpdateTime = Any() //my up-to-date timestamp. I first assign it some date in the past, to make sure it gets the first document added.
// some code
talksListener = path.whereGreaterThan("timestamp", lastUpdateTime)
.addSnapshotListener(EventListener<QuerySnapshot> { snapshot, e ->
if (snapshot != null && !snapshot.isEmpty && !snapshot.metadata.hasPendingWrites()) {
for (dSnapshot in snapshot) {
val thisTimestamp = dSnapshot.get("timestamp")
if (thisTimestamp != null) {
lastUpdateTime = thisTimestamp
}
}
}
})
But every time I add an document, I get the whole collection again.
I also tried all combinations with orderBy and startAt/endAt/startBefore/EndBefore but the result is the same. Either I get nothing, or the whole collection every time a new document is added.
for example:
talksListener = path.orderBy("timestamp").startAfter(lastUpdateTime)
Where is the problem here?
Also, on a different note, is there a possibility to include !snapshot.metadata.hasPendingWrites() into the query in Kotlin. The documentation says to use MetadataChanges.INCLUDE but I do not get how to implement it in Kotlin. Every Hint is much appreciated.
edit 1:
My firestore DB is structured like this:
users/{user}/messages/{message} -> here is the timestamp located
and my path leads to ./messages
edit 2:
the solution is to detach and reattach the listener after the new lastUpdateTime is assigned. That does not sound good to me, so if anyone has a better solution, I am happy to hear it. For the time being I will stick to it though.
I got a recyclerView that will populate according to a JSON result using databinding, what i want to do is to check/compare the start date & expired date to see is the "Deals" is expired (if expired a textview with text "DEALS EXPIRED" will appear)
"DealsPageInfo": [
{
"DisplayName": "string",
"StartDate": "2018-04-27T03:06:18.890Z",
"ExpiredDate": "2018-04-27T03:06:18.890Z",
"Url": "string",
"ImageUrl": "string",
"ShortDescription": "string"
}
Here is some question from me:
* should i use DATE / String to store the object?
* where should i perform this action? under my fragment / adapter?
Appreciate if any source / example provided.
<TextView
android:id="#+id/list_offers_startDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="3dp"
android:text="#{offers.StartDate}"
android:textColor="#color/colorGrayText"
android:textSize="#dimen/list_fontsize"
/>
<TextView
android:id="#+id/list_offers_endDate"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="3dp"
android:text="#{offers.ExpiredDate}"
android:textColor="#color/colorGrayText"
android:textSize="#dimen/form_fontsize"
/>
* where should i perform this action? under my fragment / adapter?
perform this in onBindViewHolder of your adapter,
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int position){
if (isDateExpired(listItems.get(position).getStartDate(),listItems.get(position).getEndDate())){
viewHolder.dealsExpiredtextview.setVisibility(View.GONE);
}else {
viewHolder.dealsExpiredtextview.setVisibility(View.VISIBLE);
}
}
add this method in your adapter,
public boolean isDateExpired(String startDate, String endDate) {
SimpleDateFormat dfDate = new SimpleDateFormat("dd-MM-yyyy");
boolean b = false;
try {
if (dfDate.parse(startDate).before(dfDate.parse(endDate))) {
return true; // If start date is before end date.
} else if (dfDate.parse(startDate).equals(dfDate.parse(endDate))) {
return false; // If two dates are equal.
} else {
return false; // If start date is after the end date.
}
} catch (ParseException e) {
e.printStackTrace();
return false;
}
}
should i use DATE / String to store the object?
Yes you have to save both values in Date or string.
where should i perform this action? under my fragment / adapter?
You have to perform this function in your adapter. while populate data to view.
compare date :
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
Date StartDate= sdf.parse(StartDate);
Date ExpiredDate= sdf.parse(ExpiredDate);
if (StartDate.after(ExpiredDate)) {
//create your logic here
}
Hope it will help you!!
You can use timestamp to do this kind of time checking thing. Send start and end timestamp in your json. And you can do this in your adapter.
Yes, I think you should use Date to represent start date and whatever other date you have, it makes more sense.
I don't think your Adapter/View is the best place do to this conversion. You should either have your parser do that for you OR you could do some post processing on your List of objects once they have been fetched from the network. Preferably even on a background thread.
Parsing those Strings to Dates in your Adapter is kind of wasteful and might make your RecyclerView a bit laggy. It will cause for repeated calculations of the same values and possibly a lengthy date parsing on the UI thread.
Firstly if you want change textview text to "DEALS EXPIRED" you should perform action under your adapter.
If you don't want parse string again you can store date as Date object.
You can parse your date like this.
Instant instant = Instant.parse( "2018-04-27T03:06:18.890Z" );
Date date = java.util.Date.from( instant );
if ( Calendar.getInstance().after( date ) ) {
// if this statement is true deal is expired.
}
I have some data in FirebaseDatabase in which every data set has two properties: startTime and endTime.
Here's the data-structure:
app
-ref
-uniqueID1
-key: value
-startTime: 1488849333
-endTime: 1488853842
-key: value
-uniqueID2
-key: value
-startTime: 1488850198
-endTime: 1488853802
-key: value
What I want is to deleted the data set when the endTime has passed automatically or when the user opens the app.
I have done some research on this topic and found this, but this doesn't seems helpful to me.
How can I remove the datasets whose endTime has passed?
This looks like a similar answere but you seem not to understand the answer. So here is how to do it.
Since what matters is the end time only we are going to monitor when it has passed. To do this, we get the current time
Date().getTime();
and check whether its greater than the end time(if it is, it means that the end time has passed)
final DatabaseReference currentRef = adapter.getRef(position);
currentRef.child("endTime").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
long time = System.currentTimeMillis(); //get time in millis
long end = Long.parseLong( dataSnapshot.getValue().toString()); //get the end time from firebase database
//convert to int
int timenow = (int) time;
int endtime = (int) end;
//check if the endtime has been reached
if (end < time){
currentRef.removeValue(); //remove the entry
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
i have implemented that code when the item i want to remove is clicked. so the adapter is from a listview.
Thanks, i hope it helps