Displaying time relative to a given using luxon library - luxon

Does luxon support feature for Displaying time relative to a given?
Moment has "Calendar time" feature:
https://momentjs.com/docs/#/displaying/calendar-time/
moment().calendar(null, {
sameDay: '[Today]',
nextDay: '[Tomorrow]',
nextWeek: 'dddd',
lastDay: '[Yesterday]',
lastWeek: '[Last] dddd',
sameElse: 'DD/MM/YYYY'
});
Could I achieve same using luxon?

From version 1.9.0 you can use toRelativeCalendar:
Returns a string representation this date relative to today, such as "yesterday" or "next month" platform supports Intl.RelativeDateFormat.
const DateTime = luxon.DateTime;
const now = DateTime.local();
// Some test values
[ now,
now.plus({days: 1}),
now.plus({days: 4}),
now.minus({days: 1}),
now.minus({days: 4}),
now.minus({days: 20}),
].forEach((k) => {
console.log( k.toRelativeCalendar() );
});
<script src="https://cdn.jsdelivr.net/npm/luxon#1.10.0/build/global/luxon.js"></script>
Before version 1.9.0, there was no calendar() equivalent in Luxon.
The For Moment users manual page stated in the DateTime method equivalence => Output => Humanization section:
Luxon doesn't support these, and won't until the Relative Time Format proposal lands in browsers.
Operation | Moment | Luxon
---------------------------------------------------------------------------------------
"Calendar time" | calendar() | None (before 1.9.0) / toRelativeCalendar() (after 1.9.0)
If you need, you can write something by yourself, here a custom function example that has a similar output of moment's calendar():
const DateTime = luxon.DateTime;
function getCalendarFormat(myDateTime, now) {
var diff = myDateTime.diff(now.startOf("day"), 'days').as('days');
return diff < -6 ? 'sameElse' :
diff < -1 ? 'lastWeek' :
diff < 0 ? 'lastDay' :
diff < 1 ? 'sameDay' :
diff < 2 ? 'nextDay' :
diff < 7 ? 'nextWeek' : 'sameElse';
}
function myCalendar(dt1, dt2, obj){
const format = getCalendarFormat(dt1, dt2) || 'sameElse';
return dt1.toFormat(obj[format]);
}
const now = DateTime.local();
const fmtObj = {
sameDay: "'Today'",
nextDay: "'Tomorrow'",
nextWeek: 'EEEE',
lastDay: "'Yesterday'",
lastWeek: "'Last' EEEE",
sameElse: 'dd/MM/yyyy'
};
// Some test values
[ now,
now.plus({days: 1}),
now.plus({days: 4}),
now.minus({days: 1}),
now.minus({days: 4}),
now.minus({days: 20}),
].forEach((k) => {
console.log( myCalendar(now, k, fmtObj) );
});
<script src="https://cdn.jsdelivr.net/npm/luxon#1.8.2/build/global/luxon.js"></script>
This code roughly inspired from moment code, it can be definitely improved.

Related

Retrieve and compare the style attribute of an element periodically using using cypress

I have a time indicator that travels over a timescale, the indicator's style attribute value keeps on changing for every x milliseconds and I need to get, store and compare that the previously captured value is greater than the latest value.
Initial value:
Latest value:
The logic is, from one point (left 10), every second it moves to the left (left -0, -1, -2, -3 ...)
I tried few ways and one of them is to capture in the same 'cy.then', but in that case, the element will not have the recent value. So far, I tried this. it fetches the value and with some help of regex, I got a 'comparable' value but how I can store/compare those values? Additionally, what is the best way if we need to compare more than 2 values?
const BTN_CONTROL_TIMEINDICATOR = '#currentTimeIndicator'
static verifyTimeLapse() {
//wip
var initialVal, nextVal
initialVal = this.getAnyValueOfAnElement(BTN_CONTROL_TIMEINDICATOR)
cy.wait(500)
nextVal = this.getAnyValueOfAnElement(BTN_CONTROL_TIMEINDICATOR)
cy.log(initialVal > nextVal)
}
static getAnyValueOfAnElement(element) {
//wip
cy.get(element)
.then(($ele) => {
const val=$ele.attr('style').replace(/[^\d.-]/g, '')
cy.log(val)
// return does not work
})
}
cy.log:
Page objects don't work very well with the Cypress command queue, here's what you might do with custom commands.
/* Get the numeric value of CSS left in px */
Cypress.Commands.add('getTimescaleValue', () => {
cy.get('#currentTimeIndicator')
.then($el => +$el[0].style.left.replace('px',''))
})
/* Get a sequence of time scale values */
Cypress.Commands.add('getTimescaleValues', ({numValues, waitBetween}) => {
const values = [];
Cypress._.times(numValues, () => { // repeat inner commands n times
cy.getTimescaleValue()
.then(value => values.push(value)) // save value
.wait(waitBetween)
})
return cy.wrap(values);
})
/* Assert a sequence of values are in descending order */
Cypress.Commands.add('valuesAreDescending', { prevSubject: true }, (values) => {
values.reduce((prev, current) => {
if (prev) { // skip first (no prev to compare)
expect(prev).to.be.gt(current) // assert pairs of values
}
return current
});
})
it('check the timeline', () => {
cy.getTimescaleValues({ numValues: 10, waitBetween: 100 })
.valuesAreDescending()
})
Log
assert
expected 63 to be above 58
assert
expected 58 to be above 48
assert
expected 48 to be above 43
assert
expected 43 to be above 33
assert
expected 33 to be above 23
assert
expected 23 to be above 18
assert
expected 18 to be above 13
assert
expected 13 to be above 3
assert
expected 3 to be above -2
Tested with
<div id="currentTimeIndicator" style="left:63px">Target</div>
<script>
const timer = setInterval(() => {
const div = document.querySelector('#currentTimeIndicator')
const left = +div.style.left.replace('px', '');
if (left < 0) {
clearInterval(timer)
return
}
const next = (left - 5) + 'px';
div.style.left = next;
}, 100)
</script>
If your app uses setInterval() for timing, you should be able to use cy.clock() and cy.tick() instead of .wait(waitBetween) to get more precise sampling and faster test execution.
I don't know where the initial value comes from. But before it changes, maybe on page load, maybe as first job on click, etc you can do something like this:
let item = document.querySelector("#currentTimeIndicator");
item.dataset.left = parseFloat(item.style.left);
console.log(item);
<div id="currentTimeIndicator" style="left:-20px"></div>

xdan/datetimepicker use "momenjs" instead default "php-date-formatter" - the "Highlighted days" functionality not working

I am trying to use datetimepicker and I have these functions to override date formatting. In other places we use momentjs for date time formatting.
There is my plunker example.
Date.parseDate = function (input, format) {
return moment(input, format).toDate();
};
Date.prototype.dateFormat = function (format) {
return moment(this).format(format);
};
Use momentjs formats for datetimepicker:
format: "DD/MM/YYYY H:mm:ss",
formatTime: 'H:mm',
formatDate: 'DD/MM/YYYY',
But when using moment the "highlighted days" function does not work.
How to make that "highlighted days" function were working?
Found solution:
$(document).ready(function() {
var myFormatter = {
parseDate: function(vDate, vFormat) {
return moment(vDate, vFormat).toDate();
},
guessDate: function(vDateStr, vFormat){
return moment(vDateStr, vFormat).toDate();
},
parseFormat: function(vChar, vDate){
return vDate; // date string (I guess)
},
formatDate: function(vChar, vDate) {
return moment(vChar).format(vDate);
},
};
jQuery.datetimepicker.**setDateFormatter**(myFormatter);
jQuery('#datetimepicker').datetimepicker({
timepicker: true,
// 'd/m/y'format is requared for datetimepicker days HIGHLIGHT function to work!!!
//Date, time formating: http://php.net/manual/en/function.date.php
step: 15,
/*
// momentJs formating
format: "d/m/Y H:i:s",
formatTime: "H:i",
formatDate: "d/m/Y",
*/
format: "DD/MM/YYYY H:mm:ss",
formatTime: 'H:mm',
formatDate: 'DD/MM/YYYY', //I need to use this format, but it works only when using "d/m/Y" - so somewhere the php date formater is still used..
highlightedDates: [
"01/09/2016,,xdsoft_highlighted_mint",
"02/09/2016,,xdsoft_highlighted_mint",
"03/09/2016,,xdsoft_highlighted_mint",
"06.09/2016",
"07.09.2016",
"08.09.2016",
"12.09.2016,Christmas Eve,xdsoft_highlighted_mint",
"13.09.2016,Christmas Day,xdsoft_highlighted_mint",
"14.09.2016,Christmas Day,xdsoft_highlighted_mint",
"26.09.2016,,xdsoft_highlighted_mint"
]
});
There is working plunker example
The main issues are is my case is browserify/gulp modules concatenation.. And that datetimepicker is undefined under jquery...
So trying to change building to WebPack....

Meteor aldeed collections2 update data to array of objects using for loop

Hello Now i have a problem. I want to insert data to array of objects using for loop
fields:{
type:[Object],
label:"Fields",
optional:true
},
"fields.$.category":{
type:String,
label: "Category"
},
"fields.$.sub":{
type:String,
label:"Sub Category",
},
And using savaData.js in server i tried
// ServiceProviders.update({
// '_id':"GmkGSXjyNFshomdCu"},
// {
// '$set': {'fields':{
// '$.category':categorydata,
// '$.sub':subdata
// }}
// },function(error,result){console.log(error);console.log(x+y);});
and
ServiceProviders.update(
{'_id': 'JN4mRPfJZqBadZtPY' },
{'$set': {'fields.0.category': categorydata,'fields.0.sub':subdata}},
true );
then
var x = "fields."+i+".category";
var y = "fields."+i+".sub";
x=x.toString();
y=y.toString();
ServiceProviders.update(
{'_id': 'JN4mRPfJZqBadZtPY' },
{'$set': {x: categorydata,y:subdata}},
true );
I got Different errors every time could you please help me in this issue
Currently, $ Does not work on Meteor js.
So you have to create a fields object on either server side or client side:
var fieldsData = []
for (var i = 0; i < categorydata.length || i < subdata.length ; i++ ){
fieldsData.push({
category : ( categorydata[i] ? categorydata[i] : '' ),
sub : ( subdata[i] ? subdata[i] : '' )
})
}
ServiceProviders.update(
{'_id': 'JN4mRPfJZqBadZtPY' },
{'$set': {fields : fieldsData}},
true );
Please make sure for either every filds data have cat and subcat value or make cat and subcat cat optional true.

Meteor/ng2: Where to process a variable that requires two subscription to be resolved

Assume I have
this.subscribe('a', () => {this.allA = A.find();});
this.subscribe('b', () => {this.allB= B.find();});
And a variable that is something like
let x = *take the first A, do some calculation to get the B linked, return B*
Where such logic be put to be sure this is only processed when subscriptions 'a' and 'b' are resolved ?
Might be using zones but I am not 100% what could be the best way to do it in a #Component.
PS: avoid do-a-serverside-method :D
Regards
Instead of using callbacks in your subscriptions, return subscription handles and then check their ready() state:
const subA = this.subscribe('a');
const subB = this.subscribe('b');
const that = this;
Tracker.autorun(()=>{
if ( subA.ready() ) that.allA = A.find();
if ( subB.ready() ) that.allB = B.find();
if ( subA.ready() && subB.ready() ) {
let x = ... //compute x
}
});
The solution seems for now to be to wrap it in a autorun (MeteorComponent for instance)
this.autorun(()=>{
let s1 = this.subscribe('a', () => {this.allA = A.find();});
let s2 = this.subscribe('b', () => {this.allB= B.find();});
if(s1.ready() && s2.ready())
...

Preferred method to reduce/filter a Map in Dart?

Trying to find the cleanest way to reduce a Map in Dart. Looking for something akin to JavaScript's Array.prototype.filter()
Any suggestions? The following method leaves a lot to be desired:
Map ingredients = {
'flour': '250g',
'butter': '50g',
'egg': 1,
'water': '0.2l'
};
final flour = new Map.fromIterable(
ingredients.keys.where((k) => ingredients[k] == '250g'),
value: (k) => ingredients[k]
);
print(flour); // {flour: 250g}
There is no built in support for Pairs in the core library. However if you find yourself doing this type of thing often, you could write a utility library. For example:
library pairs;
class Pair<K,V> {
Pair(this.k, this.v)
final K k;
final V v;
String toString() => '($k, $v)';
}
Iterable<Pair> asPairs(Map map) => map.keys.map((k) => new Pair(k, map[k]));
Map fromPairs(Iterable<Pair> pairs) => new Map.fromIterables(
pairs.map((p) => p.k),
pairs.map((p) => p.v));
Then you can use it like this:
import 'src/pairs.dart';
Map flour = fromPairs(asPairs(ingredients).where((p) => p.v == '250g'));
print(flour); // {flour: 250g}
Perhaps this is something that could be contributed to the quiver package, a set of non-core utilities.
There is now a map property to get all Map entries.
So you can do:
void main() {
Map ingredients = {
'flour': '250g',
'butter': '50g',
'egg': 1,
'water': '0.2l'
};
var flour = Map.fromEntries(
ingredients
.entries
.where((e) => e.value == '250g'),
);
print(flour);
}
You would play with e.key if you were interested in the key's value.
Concerning a reduce method, you could use the fold method on the filtered entries List.

Resources