LWC Date input Calculator - javascript

I am trying to get a correct outcome on difference of two dates. But when I do this I am getting a result such as (ex.10211438742389) instead of 1, 2, 3, 4, etc.. This is my JavaScript code.
import Division from '#salesforce/schema/User.Division';
import { LightningElement, track } from 'lwc';
export default class LightningExampleInputDate extends LightningElement {
#track date1;
#track date2;
#track result;
datehandler1(event) {
this.date1 = Date.now();
console.log(event.target.value)
}
datehandler2(event) {
this.date2 = new Date(event.target.value);
console.log(event.target.value);
}
resulthandler() {
this.result = Math.abs(this.date2 - this.date1);
console.log(this.result);
}
}
I am expecting a shorter value to come out when I check the difference in-between two dates.

Dates in javascripts is a representation of milliseconds starting from the epoch date, which is 1st of Jan 1970.
If you want to calculate the difference of two dates in days, you could try this solution: https://stackoverflow.com/a/3224854/1964104

Related

How can I prevent the variable from being undefined?

Update:
I checked if setDate() is called from ngOnInit: it is.
Also I specified the variables: rentalStartInput is an string Array and contains the real dates with I get from the other component (see picture below).
rentalStart is a Date, right now it is hard-coded, which I want to change. rentalStart should countain the start day of a range which I got from rentalStartInput. Current I write it manually, to see if highlighting dates works. (it does)
Update end
I'm a beginner with typescript/angular and I'm having the problem of not being able to access variables.
I have some rentals which have a start and end date. I want to display those in a calendar like the following:
Currently I get it out that the range is displayed as in the picture, but only hard-coded.
TypeScript:
#Component({
selector: 'app-calendar',
templateUrl: './calendar.component.html',
styleUrls: ['./calendar.component.css']
})
export class CalendarComponent implements OnInit {
// #Input() rentalStartInput: String[]; //error: Property 'rentalStartInput' has no initializer and is not definitely assigned in the constructor.
#Input() rentalStartInput: String[] = [];
#Input() rentalEndInput: String[] = [];
rentalStart: Date = new Date(2023-1-1);
rentalEnd: Date = new Date(2023-1-1);
getDaysFromDate(month: number, year: number) {
const startDate = moment(`${year}/${month}/01`)
const endDate = startDate.clone().endOf('month')
this.dateSelect = startDate;
const diffDays = endDate.diff(startDate, 'days', true)
const numberDays = Math.round(diffDays);
this.monthSelect = Object.keys([...Array(numberDays)]).map((a: any) => {
a = parseInt(a) + 1;
const dayObject = moment(`${year}-${month}-${a}`);
return {
name: dayObject.format("dddd"),
value: a,
indexWeek: dayObject.isoWeekday(),
selected: this.isInRange(a, month, year),
};
});
}
isInRange(day: any, month: any, year: any) {
let rangeDay = new Date(year, month - 1, day);
this.rentalStart = new Date(2023, 0, 6); //hard-coded, what I want to change
this.rentalEnd = new Date(2023, 0, 17)
let rentalRange = moment.range(this.rentalStart, this.rentalEnd);
return rentalRange.contains(rangeDay); //true if day is in range -> highlighted in ui
}
}
When I try to get access to variables rentalStartInput and rentalEndInput it doesnt work. I want to replace rentalStartand rentalEnd with them. I also don't want to do the assignment within the method, because then it's done 31 times. But when I change it to a new method, rentalStart and rentalEnd are undefined.
How can I assign both variables and use them in isInRange?
#Component({
selector: 'app-calendar',
templateUrl: './calendar.component.html',
styleUrls: ['./calendar.component.css']
})
export class CalendarComponent implements OnInit {
#Input() rentalStartInput: String[] = [];
#Input() rentalEndInput: String[] = [];
rentalStart: Date = new Date(2023-1-1);
rentalEnd: Date = new Date(2023-1-1);
ngOnInit(): void {
this.setDate();
}
setDate(){
this.rentalStart = new Date(2023, 0, 6);
this.rentalEnd = new Date(2023, 0, 17);
console.log('setDate'); //check if it is ever called from ngOnInit (it is)
}
isInRange(day: any, month: any, year: any) {
console.log(this.rentalStart); // undefined
(...)
}
}
I get the real dates from another component via #Input(). They are in separate variables: rentalStartInput and rentalEndInput
In console they look like this:
What i'm trying to do is to generate range objects to check if a day is included.
First of all, I fail getting access to the dates.
console.log(this.rentalStartInput) // see picture
console.log(JSON.stringify(this.rentalStartInput)) // []
console.log(this.rentalStartInput[0]) // undefined
console.log(Object.keys(this.rentalStartInput).length) // 0
console.log(this.rentalStartInput.length) // 0
console.log(this.rentalStartInput['1']) // undefined
What possibilities are there to access the data? I cant do a for loop unless I know the length of the array.
I hope my problem is understandable. I can provide more code if necessary.
Thank you very much for any kind of help!

How to display Hourly data based on Current Time?

I have two values, one from Hourly data and other from Current Time, where its hour is to be compared and display when found match or equal
See below code for better understanding
export class HourlyForecast extends Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
const { data } = this.props;
if(!data) return null;
const time = data.datetime
const time2 = time.slice(11,13)
console.log('HOURLY DATA', time2)
const time5 = moment.tz(this.props.timezone).format('HH:mm').slice(0,2)
console.log('TIME CURRENT', time5);
}
}
export default HourlyForecast
I want to compare the hour value from hourly data with current time's hour value. How to do it?
See the above image for reference. The Hourly data ranges from 00 to 09 whereas Current Time is 02. The Hourly data must display from 02 comparing with Current Time.
Question is not clear though you can try this to compare.
async function1(){
let hourData = await hourlyfunction()
let currentData await currentTimefunction()
return hourData==currentData
}

How to filter last day in an array?

I have an array of objects like this:
[
{
created: "2019-08-14T13:24:36Z",
email: "test1#gmail.com"
},
{
created: "2019-08-15T13:24:36Z",
email: "test2#gmail.com"
},
{
created: "2019-08-16T13:24:36Z",
email: "test1#gmail.com"
},
{
created: "2019-08-22T13:24:36Z",
email: "test4#gmail.com"
},
{
created: "2019-08-22T15:29:66Z",
email: "test1#gmail.com"
}
]
The array is sorted by created. I want to filter those records which are on the last day, irrespective of the time on that day. I added the timestamp using moment.js. Something on these lines:
router.get('/GetLastDayRecords', (req, res) => {
res.json(allRecords.filter(record => record.created.max()));
});
Split the task: first get the maximum date which you'll find at the end of the sorted array (just getting the "YYYY-MM-DD" part of it is enough) and then launch the filter:
let max = allRecords.length ? allRecords[allRecords.length-1].created.slice(0,10) : "";
res.json(allRecords.filter(({created}) => created >= max));
First you need to figure out which day is the last day. If you can assume the records are already sorted, then this is pretty simple:
// Assuming your records are stored in the variable "records"
var lastDay = records[records.length - 1].created;
Now here's where your specific answer may differ based on how you want to handle time zones. Suppose one event happened at 11 PM EST (3 AM GMT) and another event happened at 1 AM EST (5 AM GMT). Are these the same day? In Europe they are, but in America they aren't!
What you need to do is create some cipher from the date+time listed to a "day". This way you can compare two "days" to see if they're the same:
lastDay = new Date(lastDay);
// Setting hours, minutes, and seconds to 0 will give you just the "day" without the time, but by default will use the system timezone
lastDay.setHours(0);
lastDay.setMinutes(0);
lastDay.setSeconds(0);
Once you know which day was the last, it's a simple filter:
// Using a for loop
var results = []
for (var i = 0; i < records.length; i++)
{
if (records[i].created > lastDay) {
results.push(records[i]);
}
}
// Using .filter
var results = records.filter(x => x.created > lastDay);
Alternatively, since we know it's already sorted, we can do it a bit more efficiently by binary searching for the first record on the last day, then grabbing all records after that:
var test = records.length / 2;
var step = records.length / 4;
var found = false;
while (!found) {
if (records[test].created < lastDay) {
test += step;
step /= 2;
}
else if (records[test].created > lastDay) {
if (step == 1) {
// We found the exact cut-off
found = true;
}
else {
test -= step;
step /= 2;
}
}
}
var results = records.slice(test);
Because you're only interested in the "last" day, the logic is a bit simpler. If you wanted the "third" day, you would need to check if created was after the start of the third day and before the end of the third day. We can just check if it's after the start of the last day.
I would create a function to turn your created properties into data be easily compared.
I would also avoid trying to do the entire filter operation in one or two lines as it will difficult to read by other developers.
const dateToInt = date => parseInt( date.split('T').shift().replace(/-/g, '') );
The above will:
Split your created property into an array of date and time.
Select the first element, which happens to be the date.
Remove the dashes in the date.
Coerce the value into a number.
With this you can find the maximum value and filter based on that value.
const nums = foo.map( ({ created }) => dateToInt(created) )
First get a list of numbers from the dataset.
const max = Math.max( ...nums )
Get the biggest number in the list.
const lastDays = foo.filter( ({ created }) => dateToInt(created) === max )
With all that setup, getting the max date is very easy and readable.
Of course, since the list is already sorted. You could have just done this as well.
const last = foo[foo.length -1].created;
const lastDays = foo.filter( ({ created }) => created === last )
I wrote a solution using reduce and filter:
const lastDay = arr.reduce((acc, el) => {
const date = el.created.substr(0,10);
const oldDate = new Date(acc);
const nextDate = new Date(date);
if(oldDate.getTime() > nextDate.getTime()) {
return oldDate;
} else {
return nextDate;
}
}, '1900-01-01');
const lastDayArr = arr.filter(el => {
const date = el.created.substr(0,10);
const oldDate = new Date(lastDay);
const nextDate = new Date(date);
return (oldDate.getTime() === nextDate.getTime());
});
First, you find the most recent date, reducing the original array by comparing which date is the most recent, for this you drop the part of the created string that specifies the hours/minutes/seconds.
You can use a very distant in time date as initial value, or you can set it to null and add another validation in your callback function.
As a second step, you use filter, using the same technique of dropping the hours/minutes/seconds of the created string.
The end result is an array of the elements with the most recent date in your original array.
If you can assume the array is sorted, you can skip the reduce method and just do:
const lastDay = arr[arr.length - 1].created.substr(0,10);
This should work:
allRecords.filter( record => {
let last_date = allRecords[ allRecords.length - 1].created
return last_date.slice(0, 10) === record.created.slice(0, 10)
})
Basically, you are getting the last element from your array and slicing its created value down to its date. Then you are slicing your current record's created value down to its date and comparing if they are the same.
Assuming that the array is already ASC ordered:
const onLastDay = values.filter( v => {
const last = moment(values[ values.length - 1 ].created)
const differenceInDays = last.diff(moment(v.created), 'days')
return differenceInDays < 1
})
console.log(onLastDay)
NOTE: If you try with the reported array you get an error due the fact that the last date is not valid! There are 66 seconds!

Sort by date in React data grid

Is there a sort by date in the React data grid? If so, how can this be called? In the examples, all sorting works only on the line:
Example 1
Example 2
In example 2, there are columns with dates, but they are sorted as strings.
i have a solution that is really good but not great. really good in that it sorts perfectly but it isn't good if you also want to filter on the column as well.
Basically you are displaying the formated date with a custom formatter and the value you are passing to sort on is the the number of seconds from 1/1/1970 for each date so it will sort right.
And yes, i use functions instead of components for the formatter and headerRenderer values all the time and it works fine.
i work an an intranet so i can't just copy/paste my code so this is just hand typed but hopefully you get the idea.
class GridUtil {
static basicTextCell = (props)=>{
return (<span>{props.value? props.value : ""}</span>)
}
}
class AGridWrapper extends React.Component {
///////////////
constructor(props){
super(props);
this.state={...}
this.columnHeaderData = [
{
key: "dateCompleted",
name: "Date Completed",
formatter: (data)=>GridUtil.basicTextCell({value: data.dependentValues.dateCompletedFormatted}),
getRowMetaData: (data)=>(data),
sortable: true
}
];
}//end constructor
///////////////////////////////////
//Note that DateUtil.getDisplayableDate() is our own class to format to MM/DD/YYYY
formatGridData = !props.inData? "Loading..." : props.inData.map(function(obj,index){
return {
dateCompleted: rowData.compDate? new Date(rowData.compDate).getTime() : "";
dateCompletedFormatted: rowData.compDate? DateUtil.getDisplayableDate(rowData.compDate) : "";
}
});
//////////
rowGetter = rowNumber=>formatGridData[rowNumber];
/////////
render(){
return (
<ReactDataGrid
columns={this.columnHeaderData}
rowGetter={this.rowGetter}
rowsCount={this.formatGridData.length}
...
/>
}
I use react-table I was having the same issue, the solution in case, was to convert the date to a javaScript Date, and also return this as a JSon format, I have to format how the date render in the component. here is a link that shows how I did this.
codesandbox sample

Ember.js weekly calendar navigation

I'm building a simple weekly calendar component for my app and I'm struggling to find a way for creating the weeks navigation. Here's what I have so far:
/week-view/component.js
import Ember from 'ember';
export default Ember.Component.extend({
firstDay: moment().startOf('week'),
days: Ember.computed('firstDay', function() {
let firstDay = this.get('firstDay').subtract(1, 'days');
let week = [];
for (var i = 1; i <= 7; i++) {
var day = firstDay.add(1, 'days').format('MM-DD-YYYY');
week.push(day);
}
return week;
}),
actions: {
currentWeek() {
this.set('firstDay', moment().startOf('week'));
},
previousWeek() {
this.set('firstDay', moment().startOf('week').subtract(7, 'days'));
},
nextWeek() {
this.set('firstDay', moment().startOf('week').add(7, 'days'));
}
}
});
/week-view/template.hbs
<button {{action "previousWeek"}}>previous</button>
<button {{action "currentWeek"}}>current week</button>
<button {{action "nextWeek"}}>next</button>
<ul>
{{#each days as |day|}}
<li>{{day}}</li>
{{/each}}
</ul>
At the moment it works to navigate one week before and one after the current week only. Any idea on how to make this work for an unlimited number of weeks is greatly appreciated. Thanks in advance.
I think you shouldn't change your firstDay property while prepairing week array (in the computed function). It overrides momentjs state. Computed property in this case should just read firstDay property without affecting changes to it.
Also in your previous and next week actions you don't have to create new momentjs objects. You can easily operate on previously created firstDay property, for example.
this.get('firstDay').subtract(7, 'days');
But in this case, state of momentjs have changed, but emberjs doesn't see any changes. That is because your firstDay property doesn't really changed (and computed property is set to check only firstDay, it doesn't work deeply). In fact firstDay property is just reference to momentjs object, and that object has been changed, not the reference. But luckily you can manually force emberjs to reload any computed properties based on any property in this way:
this.notifyPropertyChange('firstDay');
So little bit refactored working example can looks like:
import Ember from 'ember';
export default Ember.Component.extend({
selectedWeek: moment().startOf('week'),
days: Ember.computed('selectedWeek', function() {
let printDay = this.get('selectedWeek').clone();
let week = [];
for (var i = 1; i <= 7; i++) {
week.push(printDay.format('MM-DD-YYYY'));
printDay.add(1, 'days');
}
return week;
}),
actions: {
currentWeek() {
this.set('selectedWeek', moment().startOf('week'));
},
previousWeek() {
this.get('selectedWeek').subtract(7, 'days');
this.notifyPropertyChange('selectedWeek');
},
nextWeek() {
this.get('selectedWeek').add(7, 'days');
this.notifyPropertyChange('selectedWeek');
}
}
});

Categories

Resources