I am newbie to shopify, I have to display a time counter up-to 9 PM everyday. The logic includes to deduct current time from specified time and the difference time will display as counter(remaining time).
I am able to retrieve current timestamp in shopify using the code below
{% assign timestamp = 'now' | date %}
Now I have a date "21-03-2016 21:00:00" and wants to convert in timestamp but not able to get the solution.
Let me know if any one can help me in this. Thank You.
Note that the value will be the current time of when the page was last
generated from the template, not when the page is presented to a user
if caching or static site generation is involved.
http://shopify.github.io/liquid/filters/date/
This is probably best done using Javascript, not pure-Liquid. You generally want your pages to be as cache-able as possible for Shopify's servers to keep loading times as lean as possible.
You will want to use Liquid to compensate for timezones, however. You can get the store's configured timezone and drop that into a Javascript variable:
var timezone = {{ 1 | date: '%z' | json }};
The above liquid statement takes some arbitrary input, runs it through the date filter and outputs only the timezone component configured for that store (using '%z'), then runs that through the json filter to ensure that whatever the output will always be javascript-legal.
Now that you know your timezone offset, you can assemble your timer logic in Javascript using all your normal date/time tricks. For example:
var now = new Date();
var nowStr = now.toISOString(); // Output format: '2019-01-01T00:00'
// Chop off the time portion, then append your desired time & store timezone
var closingTimeStr = nowStr.split('T')[0] + 'T21:00' + timezone;
// We make a new date using today's date/time string
var closingTime = new Date(closingTimeStr);
// And now we can do math based on the difference
var difference_ms = closingTime - now;
if(difference_ms > 0){
// Parse the difference into hours, minutes and seconds if a positive amount of time remains. Writing a better parsing function is left as an exercise for the reader.
var hours = parseInt(difference_ms / (60 * 60 * 1000) );
difference_ms %= (60 * 60 * 1000);
var minutes = parseInt(difference_ms / (60 * 1000) );
difference_ms %= (60 * 1000);
var seconds = parseInt(difference_ms / (1000) );
console.log('Hurry down! Closing in ' + hours + ' hours, ' + minutes + ' minutes, and ' + seconds + ' seconds!');
} else {
// Show appropriate message if we're out-of-bounds
console.log('Closed for today - try again tomorrow!');
}
Related
I want to make estimate time when user will come. I have 2 variable to save, open and closed time of the store.
$openTime = Carbon::parse($open);
$closedTime = Carbon::parse($closed);
i can get the duration between 2 variable. And i can get duration for each person who come.
$Duration = $startTime->diffInSeconds($endTime);
$perpersonDuration = gmdate("H:i:s", $Duration/$quota);
The question is how to add $perpersonduration to time. In this case i want to add $perpersonduration with $opentime. So it will be like $opentime + $perpersonduration.
Please help
In Carbon there is a method called addMinutes() and you can pass the number of minutes as you won't like this
$openTime = Carbon::now(); // 02:00:00
$closeTime = Carbon::parse($openTime)->addMinutes(30); // 02:30:00
When we use D3.js, let's say for simplicity, we have data, which are stock prices:
2021-03-18 $38.10
2021-03-19 $38.60
2021-03-22 $38.80
and we use D3 to plot a line chart for the stock price, and then move the mouse around to "hover" above the prices, and it'd show the price for that date.
Right now I am using
d3.select("svg").on("mousemove", (ev) => {
const hour = xScale.invert(ev.offsetX - dimensions.margin.left).getHours();
to get the hour of where the user is hovering on. The xScale is a scale function scaleTime() from domain to range, and xScale.invert is the function that convert the range back to domain.
If the hour is 12pm or later, I consider it the next day, and if it is before or equal, I consider it the same day. This is because the stock price of 2021-03-19 is considered to be at 12:00am (the midnight), so if I am getting to 9pm, for example, the mouse cursor is really close to the next day.
And then, let's say I identified that it is 2021-03-20, then I check whether there is stock price data. But since it was a Saturday and has no stock data, I use a function to check by the following method:
I first would go back to 2021-03-19 and see if there is a stock price. (I first build a lookup table to map date to data). If there is, then use it.
But if there isn't, I just use the delta of 1 day and move further and further, so it would go to 2021-03-21 and then increment the delta and use -delta to check for 2021-03-18, so I just use a point and go "later" and "before" with an increasing delta, until I am able to find a price
In other words, I have a "first candidate" and a "second candidate". If the first candidate has data, then use it. Otherwise, try the second candidate. If still not work, then work from the first candidate and use delta of 1 day and move "later" or "before", and if not work, use a delta of 2 days, and 3 days, until I am able to find a date with data.
Then I use this price to show on screen, to report what the date and price is
But this method is a bit low level. Does D3.js already have a method to directly do that: to spit out an invert number, which is closest to the key that has data in the dataset?
There are several functions provided by d3.js which can be used, depending on the exact situation:
1. You operate in screen space and want a mapping of the current mouse position on the closest point of the visualization which represents a single data object
In that case, you would probably want to use d3-delaunay.
d3-delaunay is a fast library for computing the Voronoi diagram of a
set of two-dimensional points. One can use delaunay.find to identify the data point closest to the pointer. Here is one example.
2. If you operate in the data domain (e.g. because you have already inverted the mouse position to the data domain)
As #Gerardo Furtado points out, you can use d3.bisect.
d3.bisect finds the position into which a given value can be inserted
into a sorted array while maintaining sorted order. If the value
already exists in the array, d3.bisect will find its position
efficiently. Here is one
example.
See also: D3: What is a Bisector? and d3.bisector using Date() Object does not resolve
Another option d3.js provides is d3.scaleThreshold.
Threshold scales allow you to map arbitrary subsets of the domain to discrete values in the range. The input domain is still continuous, and divided into slices based on a set of threshold values.
The idea is the following:
You create a d3.scaleThreshold to map any date (= continuous domain) to the fixed set of valid dates given your data by mapping it to the closest date. For that you have to specify the domain as an array of n - 1 dates which are residing in between the n valid dates. The range is the array of the valid dates.
It might not be as efficient as d3.bisect depending on your data.
const data_original = [{ date: "2021-03-18", value: "38.10"},
{ date: "2021-03-19", value: "38.60"},
{ date: "2021-03-22", value: "38.80"},
];
const data_types_converted = data_original.map(d => ({"date": new Date(d.date), "value": +d.value}));
const data_just_dates = data_types_converted.map(d => d.date);
let newDate = new Date("2021-03-17");
console.log(newDate + " -> " + getClosestDate(newDate, data_just_dates));
newDate = new Date("2021-03-18");
console.log(newDate + " -> " + getClosestDate(newDate, data_just_dates));
newDate = new Date("2021-03-19");
console.log(newDate + " -> " + getClosestDate(newDate, data_just_dates));
newDate = new Date("2021-03-20");
console.log(newDate + " -> " + getClosestDate(newDate, data_just_dates));
newDate = new Date("2021-03-21");
console.log(newDate + " -> " + getClosestDate(newDate, data_just_dates));
newDate = new Date("2021-03-22");
console.log(newDate + " -> " + getClosestDate(newDate, data_just_dates));
newDate = new Date("2021-03-23");
console.log(newDate + " -> " + getClosestDate(newDate, data_just_dates));
function getClosestDate(newDate, validDates) {
const domain = [];
let midday_local;
let midday_UTC;
validDates.forEach((d,i) => {
if (i < validDates.length - 1) {
midday_local = new Date((validDates[i].getTime() + validDates[i + 1].getTime()) / 2); // midday in local time
midday_UTC = convertDateToUTC(midday_local); // midday in UTC time
domain.push(midday_UTC);
}
});
const scale = d3.scaleThreshold()
.domain(domain)
.range(validDates);
return scale(newDate)
}
function convertDateToUTC(date) {
return new Date(
date.getUTCFullYear(),
date.getUTCMonth(),
date.getUTCDate(),
date.getUTCHours(),
date.getUTCMinutes(),
date.getUTCSeconds()
);
}
<script src="https://d3js.org/d3.v6.min.js"></script>
I have a table called transactions with two relevant fields to my question, _start_timestamp_ and _end_timestamp_. I need to sum the amount of time passed between all transactions where _end_timestamp_ is not null. So, the result must be something like Total Time of Transactions: 1 hour and 18 minutes
I've tried using Carbon, but I don't know how to sum all the lines of the table using it.
foreach($timestampStarts as $timestampStart){
$time = new Carbon($timestampStart->start_timestamp);
$shift_end_time =new Carbon($timestampStart->end_timestamp);
dd($time->diffForHumans($shift_end_time));
}
You can use the MySQL TIMESTAMPDIFF function to calculate the difference:
Transaction::whereNotNull('_end_timestamp_')
->sum(DB::raw('TIMESTAMPDIFF(SECOND, _start_timestamp_, _end_timestamp_)'));
This will give you the total in seconds.
You need to retrieve the total difference in minutes. Add the total difference and retrieve the diff for humans. You can retrieve like below:
$diffForHumans = null;
$nowDate = Carbon::now();
$diffInMinutes = 0;
foreach($timestampStarts as $timestampStart){
if(!empty($timestampStart->end_timestamp)){ // if the end timestamp is not empty
$time = new Carbon($timestampStart->start_timestamp);
$shift_end_time =new Carbon($timestampStart->end_timestamp);
//Adding difference in minutes
$diffInMinutes+= $shift_end_time->diffInMinutes($time);
}
}
$totalDiffForHumans = $now->addMinutes($diffInMinutes)->diffForHumans();
After hours spent to identify a rational or a solution, my hope is now with this community !
I'm desesperatly trying to get ("read") a time entered by user in a google spreasheet and to use it correctly in a google apps script for example to create google calendar event.
The desired format is "HH:mm"
My starting point is the google apps script example provided on https://developers.google.com/apps-script/quickstart/forms
From this example I modified the parameters of the spreasheet (sorry for the french!) using the "Change locale and time zone" instructions :
settings illustration
I also changed the display format of the columns 'C' and 'D' to not have the AM/PM put in the initial example:
Start Time End Time
13:00:00 14:55:00
13:00:00 14:55:00
...
To enable debug in script editor, I removed "_" at the end of setUpConference (line 14).
I launched the script "setUpConference" in debug to check the values read from the datasheet.
My surprise is to have for the first data line
Ethics for monsters 5/15/2013 13:00:00 14:55:00 Rm 323: Minotaur's Labyrinth
the corresponding data of the variable "session"
["Ethics for monsters", (new Date(1368568800000)), (new Date(-2209115361000)), (new Date(-2209108461000)), "Rm 323: Minotaur's Labyrinth"]
and sessions[2] is showned in the script editor as:
Sat Dec 30 1899 13:50:39 GMT+0100 (CET)
I understand that having only "time" (HH:mm), the date is incomplete (so the 1899 day) but how to obtain the time "13:00:00" rather than this strange "13:50:39" ?
Ps: my calendar time zone is also GMT+0100 (CET)
some edits with more information:
I share the google spreadsheet I used for test
I simplified the code of my google app script to focus on the issue (initial code was the one provided by google on https://developers.google.com/apps-script/quickstart/forms
/**
* A special function that inserts a custom menu when the spreadsheet opens.
*/
function onOpen() {
var menu = [{name: 'Set up conference', functionName: 'setUpConference'}];
SpreadsheetApp.getActive().addMenu('Conference', menu);
}
/**
* A set-up function that uses the conference data in the spreadsheet to create
* Google Calendar events, a Google Form, and a trigger that allows the script
* to react to form responses.
*/
function setUpConference() {
/* if (ScriptProperties.getProperty('calId')) {
Browser.msgBox('Your conference is already set up. Look in Google Drive!');
}*/
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName('Conference Setup');
var range = sheet.getDataRange();
var values = range.getValues();
setUpCalendar(values, range);
}
/**
* Creates a Google Calendar with events for each conference session in the
* spreadsheet, then writes the event IDs to the spreadsheet for future use.
*
* #param {String[][]} values Cell values for the spreadsheet range.
* #param {Range} range A spreadsheet range that contains conference data.
*/
function setUpCalendar(values, range) {
// comment cal for debug
//var cal = CalendarApp.createCalendar('Test Conference Calendar');
for (var i = 1; i < values.length; i++) {
var session = values[i];
var title = session[0];
Logger.log("i= "+i+" - "+ "session[2]= " + session[2] + " | session[3] =" + session[3] );
// This formats the date as Greenwich Mean Time in the format
// year-month-dateThour-minute-second.
var formattedHour = Utilities.formatDate(session[2], "GMT+1", "HH:mm");
Logger.log("formattedHour = "+formattedHour);
var start = joinDateAndTime(session[1], session[2]);
var end = joinDateAndTime(session[1], session[3]);
var options = {location: session[4], sendInvites: true};
// comment cal and event creation
/*var event = cal.createEvent(title, start, end, options)
.setGuestsCanSeeGuests(false);
session[5] = event.getId();*/
}
range.setValues(values);
}
/**
* Creates a single Date object from separate date and time cells.
*
* #param {Date} date A Date object from which to extract the date.
* #param {Date} time A Date object from which to extract the time.
* #return {Date} A Date object representing the combined date and time.
*/
function joinDateAndTime(date, time) {
date = new Date(date);
date.setHours(time.getHours());
date.setMinutes(time.getMinutes());
return date;
}
As linked in some of the comments sheets and JS use different date epochs and they don't always play nice.
change the var values = range.getValues(); to var values = range.getDisplayValues();
this will force it to grab the cells values as string.
changing your date join function as follows will make it handle the strings(may need to ensure the dates in your spread sheet to have leading zeros):
function joinDateAndTime(date, time) {
var t = new Date(date);
t.setHours(parseInt(time.substring(0, 2)));
t.setMinutes(parseInt(time.substring(3, 5)));
return t;
}
When I load a page with a Time object and echo it out on the page through PHP, I get this:
<?= $user->last_login ?>
// 12/30/14, 5:21 pm
When I load data through ajax, it's returned to me like this:
console.log(response.user.last_login);
// 2014-12-30T17:21:31+0000
I haven't set anything different from the default CakePHP 3 setup, and I need events that are added to the page (returned via ajax) to be in the same time format as events that were pulled on page load (return via PHP).
The default output in string format for Time objects is controlled by the setToStringFormat method http://book.cakephp.org/3.0/en/core-libraries/time.html#setting-the-default-locale-and-format-string
It is a good practice to not hardcode a format there, but to only change the current locale so that the right format is selected for you,
But the format that is used to encode to json is not possible to control it via configuration as it is a standard that dates should be presented in such format when encoded in a JSON API. Instead, what you can do is alter the jsonSerialize method in your User entity:
public function jsonSerialize() {
$toEncode = parent::jsonSerialize();
return ['last_login' => (string)$this->last_login] + $toEncode;
}
What it does is converting to string the last_login property before it is encoded to json. Converting to string will then use the globally configured toString format.
You can convert the format of the date using the javascript Date object
JSFiddle
var date = new Date(response.user.last_login)
//returns a timestamp of 1419960091000
var n = date.getTime();
var day = date.getDate();
var month = date.getMonth();
month = month + 1;
//increment the month by 1 as it starts from 0
var year = date.getFullYear();
year = year.toString().substr(2,2);
//this removes the first 2 characters to give yy, remove the above line for yyyy
var hours = date.getHours();
var minutes = date.getUTCMinutes();
var period='am';
if(hours==0){ //At 00 hours we need to show 12 am
hours=12;
}
else if(hours>12){
hours=hours%12;
//remove the above line for 24 hour format
period='pm';
}
Now you can piece together the date in the required format
var last_login = day + '/' + month + '/' + year + ' ' + hours + ':' + minutes + ' ' + period;
//gives 30/12/14 5:21 pm
Hope this helps!