As my trivial experience in Javascript and React Native, I've been struggling with how to execute a function call checkValidDate right after my state for the dates have been updated.
I'm using react-native-modal-date-time-picker to choose the date.
Here's my code:
const [chosenStartDate, setChosenStartDate] = useState('');
const [chosenStartDate_unix, setChosenStartDate_unix] = useState(null);
const [chosenEndDate, setChosenEndDate] = useState('');
const [chosenEndDate_unix, setChosenEndDate_unix] = useState(null);
const handleConfirm = (day) => {
hideDatePicker(); // Set isDatePickerVisible to false
if(chosenMode){ // If true, calendar shows up for choosing starting date, false --> for choosing ending date
setChosenStartDate(moment(day).format('MMMM Do YYYY, h:mm:ss a'));
setChosenStartDate_unix(parseInt((new Date(moment(day).format()).getTime())/60000));
// Convert date to epoch time
}else{
setChosenEndDate(moment(day).format('MMMM Do YYYY, h:mm:ss a'));
setChosenEndDate_unix(parseInt((new Date(moment(day).format()).getTime())/60000));
checkValidDate(chosenStartDate_unix,chosenEndDate_unix)
// --> I know that the dates only get updated after the handleConfirm has been executed
// --> So basically, the chosenEndDate_unix passed in checkValidDate at this moment is still
// null. Therefore, I can't check it correctly
}
};
const checkValidDate = (start, end) => {
console.log('Checking')
console.log('chosenEndDate_unix', chosenEndDate_unix);
console.log('chosenStartDate_unix', chosenStartDate_unix);
if(start && end){
((end - start) >= 5)
? (console.log('VALID'))
: (alert('Please travel aleast 5 minutes, life is worth explored!'), setChosenEndDate(''))
}
}
//...
return(
//...
{isDatePickerVisible && (
<DateTimePickerModal
isVisible={isDatePickerVisible}
mode={mode}
onConfirm={(day) => {
handleConfirm(day)
// I tried to execute the checkValidDate here, but it also doesn't work
}}
onCancel={hideDatePicker}
/>
)}
)
Basically, I have 2 buttons.
One for choosing a startDate which doesn't need to be checked.
Another for choosing an endDate which needs to be checked whether It's longer that startDate for at least 5 minutes or not
When pressing startDate button, chosenMode will be set to true and vice versa for endDate button
handleConfirm is the function we'll execute when we press the OK button on the calendar. As designed in react-native-modal-date-time-picker, only when we press OK will the date chosen be passed to the onConfirm prop
How can we execute the checkValidDate right after the chosenEndDate and chosenEndDate_unix has been updated?
PLEASE HELP ME
You can use useEffect. The checkValiddate is called when chosenEndDate or chosenEndDate_unix changed.
useEffect(()=>{
checkValiddate()
}, [chosenEndDate, chosenEndDate_unix]);
The official document has more info of how it works: https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects
Thank you very much Yupeng Li. Thank to your suggestion I've come up with the solution
By the way, when we place 2 dependencies which will change at the same time like that. checkValidDate() will be executed twice. So we'll put only 1 dependency which is chosenEndDate_unix
useEffect(() => {
if(!chosenMode) checkValidDate(chosenStartDate_unix, chosenEndDate_unix)
}, [chosenEndDate_unix])
I need the help to query long collection with date range. See the below example document. I wanna query startTime field using date range.
Since I have the dueDate field stored as "timestamp" (and NOT as string or number) on Cloud Firestore, I did this to get the invoice documents with a due date on 2017:
let start = new Date('2017-01-01');
let end = new Date('2018-01-01');
this.afs.collection('invoices', ref => ref
.where('dueDate', '>', start)
.where('dueDate', '<', end)
);
NOTE: dueDate field was stored at firebase with a Date() object. e.g.: this.doc.dueDate = new Date('2017-12-25')
You could store the datetime object as Unix time (seconds since 1 January 1970). Then you can simple use the where select like this:
collectionRef.where("startTime", ">=", "1506816000").where("startTime", "<=", "1507593600")
Btw - to convert from datetime to Unix time in your app, you can use the excellent (now deprecated) library moment (if you are building something with js or node).
var startfulldate = admin.firestore.Timestamp.fromDate(new Date(1556062581000));
db.collection('mycollection')
.where('start_time', '<=', startfulldate)
.get()
.then(snapshot => {
var jsonvalue: any[] = [];
snapshot.forEach(docs => {
jsonvalue.push(docs.data())
})
res.send(jsonvalue);
return;
}).catch( error => {
res.status(500).send(error)
});
const event = new Date();
const expirationDate = admin.firestore.Timestamp.fromDate(event);
const query = collectionRef.where('startTime', '<=', expirationDate)
As startTime stored as Timestamp, you can do this query range for more accururate (this good for both condition of long date range or same date range).
const start = new Date('2021-01-01T00:00:00.000z');
const end = new Date('2021-03-01T23:59:59.000z');
db.collection('Data').where('startTime', '>=', start).where('startTime', '<=', end).get().then(data => {
//pass your 'data' here
});
I used this in my Node.js apps. Hopefully this useful.
For everyone recently using Firebase Firestore, there's a difference depending on your settings of your Firebase implementation (depending on the firebase version).
Before, Firestore was saving Timestamp as a Date, however as described here in the docs the will be replaced soon by a Timestamp object. See the Timestamp docs here.
You can force your implementation already by adding a setting in your code to force Firebase to use Timestamp objects instead of Date like this example:
var firebaseApp = firebase.initializeApp({
apiKey: [APIKEY],
authDomain: [FIREBASEAPPDOMAIN],
projectId: [PROJECTID]
});
var firestore = firebase.firestore();
var settings = { timestampsInSnapshots: true }; // force Timestamp instead of Date
firestore.settings(settings);
The solution is to use Date.now(). Stop using timestamp service from Firebase, you need to work with the numerical value of the time in milliseconds like for example: 1514271367000, instead if Firestore uses 26/12/2017 1:56:07 GMT- 0500 (-05) will not work. An example of a query is:
this.fsService.afs.collection('chats/4bY1ZpOr1TPq8bFQ3bjS/finance/123+finance/12345'
, ref => ref.orderBy('hour').startAt(1514184967000).endAt(1514271367000))
.valueChanges().subscribe(data =>{
this.mensajes = data;
})
Those who, like me, are using PHP to access Firestore, can do something like this:
$startTime = new DateTime('2020-05-23 00:00:00');
$endTime = new DateTime('2020-06-23 23:59:59');
$start = new Google\Cloud\Core\Timestamp($startTime);
$end = new Google\Cloud\Core\Timestamp($endTime);
// fb is a Google\Cloud\Firestore\FirestoreClient object
$this->query = $this->fb->collection('your_collection');
$aux = $this->query;
$aux = $aux->where('startTime', '<', $end);
$aux = $aux->where('startTime', '>', $start);
return $aux->documents();
Enjoy.
Generic function to find documents in a collection by date range of specifics fields:
public List<QueryDocumentSnapshot> findDocsByDateRange(
String collection,
String fieldStartDate,
String fieldEndDate,
Date startDate,
Date endDate) {
ApiFuture<QuerySnapshot> querySnapshot = fireStore()
.collection(collection)
.whereGreaterThanOrEqualTo(FieldPath.of(fieldStartDate), startDate)
.whereLessThanOrEqualTo(FieldPath.of(fieldEndDate), endDate)
.get();
return querySnapshot.get().getDocuments();
}
Packages:
import com.google.api.core.ApiFuture;
import com.google.cloud.firestore.DocumentSnapshot;
import com.google.cloud.firestore.FieldPath;
import com.google.cloud.firestore.Firestore;
import com.google.cloud.firestore.QueryDocumentSnapshot;
import com.google.cloud.firestore.QuerySnapshot;
In a frontend application, this is how Firebase timestamps and dates can be used to query and store documents.
What worked for me was
Format Date with Moment JS and split into Day, Month & Year
const currentDate = moment().format("DD-MM-YYYY").split("-");
const currentDay = currentDate[0];
const currentMonth = currentDate[1];
const currentYear = currentDate[2];
const allDocuments = await collectionRef
.doc(docId)
.collection(*COLLECTION NAME*)
.where(
*DATE PARAMETER NAME*,
">=",
new Date(`${currentYear}-${currentMonth}-${currentDay}`)
)
.where(
*DATE PARAMETER NAME*,
"<",
// ${parseInt(currentDay) + *Number of days you want in range*}
new Date(`${currentYear}-${currentMonth}-${parseInt(currentDay) + 1}`)
)
.get();
I think this will help you out,
yourMethod() {
var date = DateTime.now();//
print("First Date > " + DateTime(date.year, date.month, 1).toString());
var datex = new DateTime(date.year, date.month + 1, 0);
print("Last Date > " +datex);//
//
Firestore.instance
.collection('biling')
.where("driverId", isEqualTo: widget.uid)
.where("date",
isGreaterThanOrEqualTo:
new DateTime(date.year, date.month, 1).toString())//1
.where("date", isLessThanOrEqualTo: datex.toString())//2
.orderBy('date', descending: true)
.getDocuments()
.then(
(QuerySnapshot snapshot) => {
snapshot.documents.forEach((f) {
if (this.mounted) {
setState(() {
totalP += double.tryParse(f.data["price"]);
});
}
print("_price " + f.data["price"]);
print("_duePaymntForCompay " + f.data["duePaymntForCompay"]);
}),
},
);
}
now you need to use these queries for filtering documents with conditions
because .where() is not working for me
db.collection("id").whereGreaterThan("field","value")
.whereEqualTo("field","value")
.whereLessThen("field","value")
I'm working with eBay api and trying to turn the endTime field which is in a dateTime format into a field that shows how much time is left in an auction, such as 5 minutes or 5 hours or 5 days.
In node, i'm making call to eBay api and mapping the endTime field into a variable, using the moment function.
It looks like this:
var moment = require("moment");
moment().format();
const cardsData = newData.map(card => ({
timeLeft: moment(
card.listingInfo && card.listingInfo[0].endTime
).fromNow()
Every value in the loop is returning 'a year ago'.
This is what the actual endTime field looks like
endTime: [
"2019-12-25T18:37:33.000Z"
],
where am i going wrong? does this date need to be formatted somehow before I can use moment?
So turns out adding a new Date wrapper gets this working. But i'm not exactly sure why. If anyone has any input, would be happy to hear. Thanks
timeLeft: moment(
new Date(card.listingInfo && card.listingInfo[0].endTime)
).fromNow()
As #RobG pointed out, this is incorrect. Sorry.
The expression you pass to moment(card.listingInfo && card.listingInfo[0].endTime) is a boolean expression, evaluating to true or false. Instead, I would filter newData where card.listingInfo is valid like this:
newData = newData.filter(card => {
return card.listingInfo && card.listingInfo[0];
});
Then for map you would do:
newData.map(card => ({
timeLeft: moment(card.listingInfo[0])
})
i'm working ing a react js project and I'm using antd.design Library to show a RangePicker
what i'm trying to solve is how can i get the start date and the end date from this RangePicker when user select a period
that's my code :
handleChangeDebut =range => {
const valueOfInput1 = moment(range.startDate).format();
const valueOfInput2 = moment(range.endDate).format();
console.log('start date',valueOfInput1);
console.log("end date",valueOfInput2);
}
<DatePicker.RangePicker
style={{ width: "100%" }}
getPopupContainer={trigger => trigger.parentNode}
onChange={this.handleChangeDebut}
/>
the issue is on my handleChange function , i always get the date of the current day
is there any attributes in antd design that give us the startDate and the EndDate Selected ?
Thank you for your precious help .
From the documentation, this is the signature of the onChange function function(dates: moment, moment, dateStrings: string, string), It looks like start and end date are passed as an array in the first param:
handleChangeDebut = (range) => {
const valueOfInput1 = range[0].format();
const valueOfInput2 = range[1].format();
console.log('start date',valueOfInput1);
console.log("end date",valueOfInput2);
}
Currently I have a timestamp field with value format like 1479664146607.
What I wanted to do is to get all data with timestamp that has a year of let's say 2017.
My current code is non-performant. It gets all the data, and then uses a filter method.
Let's say I got 2000+ records.
const records = []; // all records
const data = records.filter(r => new Date(r).getYear == '2017');
While this code works, it kills the server.
My database is nedb and using feathersjs, I can actually get equality items by
app.service('messages').find({
query: {
timestamp: '2017'
}
});
This code will not work because it will search for the exact year. I am looking for a way to convert the timestamp field to a year before searching it in the database.
Okay, so what I did is to use the $gt and $lt operators.
Let's say we want to get all data in year 2018.
Using momentjs, I did something like this:
const year = '2018';
// Get previous year based on given year
const previousYear = moment(year, 'YYYY').subtract(1, 'year').format('YYYY');
// Get next year based on given year
const nextYear = moment(year, 'YYYY').add(1, 'year').format('YYYY');
// get full ending date of previous year
const endOfPreviousYear = moment(previousYear, 'YYYY').endOf('year').format('x');
// get full starting date of next year
const startOfNextYear = moment(nextYear, 'YYYY').startOf('year').format('x');
// get data where year is greater than `endOfPreviousYear` and less than `startOfNextYear`
const yearQuery = {
$gt: +endOfPreviousYear,
$lt: +startOfNextYear
}
app.service('messages').find({
query: {
timestamp: yearQuery
}
});