Age Check and jquery - javascript

Does anyone have any solid examples of how to implement a jQuery or javascript based age checker? I'm looking to send someone to a page where they need to enter in the Day, Month and Year at least once a day when they hit any page on the site. Once they validate as 18 then they would not be pestered again until the next day if they return.
Any ideas?

A cookie-based solution does seem a logical fit since you can programmatically modify them from JavaScript and you can set their expiry. Calculating the date in pure JavaScript can be done as such:
var millisPerYear = 1000 * 60 * 60 * 24 * 365;
var birthdate = new Date(year, month, day); // from user input.
var age = ((new Date().getTime()) - birthdate.getTime()) / millisPerYear;
// Now set the "age" cookie.
All that is left is for your server-side response handlers to return content conditionally based on the value of the "age" cookie from the request agent.

There seem to be a number of existing resources on the web for implementing similar functionality. All of them create a cookie with the birth day selector which held by the user and can be set to expire a day later. Obviously this can be a problem if your users don't have cookies enabled. Below are a couple of examples.
http://www.webdesignforums.net/php-67/age_verification_script-30188/index2.html
http://www.techerator.com/2010/09/how-to-perform-age-verification-with-jquery-and-cookies-mmm-cookies/

There is a wonderful Date library for JavaScript called DateJS. It makes date operations extremely simple.
Your first step is, of course, to parse the date that is provided. DateJS provides a lot of parsing functionalities, such as:
Date.parse("Mar 3 2010");
Date.parse('March 20th 1973');
Date.parse("03 12 2010");
Once you have parsed the date, you can compare it to the date 18 years ago. This is also easy with DateJS
var userBDay = Date.parse("Mar 3 1970");
var eighteenYearsAgo = (18).years().ago();
var is18 = (userBDay >= eighteenYearsAgo);
You are of course assuming the user is honest. Not to mention JS can be disabled, or modified client side. But that is an entirely different discussion.
EDIT: Had forgotten about your mention of only doing verification once a day. This would require either:
Cookie (client side)
HTML5 LocalStorage (client side)
Session, where last verification can be provided either at the time of the page rendering or through an AJAX request. (server side w/ client side component)

Related

How to store birthdays in a database with timezone support?

I am using JavaScript and a PostgreSQL database, I would like to store birthdays and notify users at 12pm in their own timezone, currently I am converting dates from their timezone to my local server time and check every hour to see if a date and time matches
import { parseFromTimeZone } from "date-fns-timezone";
const userInput = "08-11" // day/month
const timeZone = "Europe/Amsterdam"
const date = parseFromTimeZone(`2000-${userInput} 00:00:00`, { timeZone });
// This is what I store in my database
const dateToStore = date.toISOString().slice("2000:".length).split(":")[0];
// This is what I run every hour
await Birthday.find({
where: {
date: new Date().toISOString().slice("year:".length).split(":")[0],
},
});
The problem is that this solution is not very dynamic because if I migrate my server it breaks, my questions are:
How can I store the birthdays? Assume users provide the month, day and time zone
In what interval can / should I check to see if a birthday message should be sent? (00:00) in the user's time zone and specified date
What would that check look like?
I have date-fns available but I do not mind using other libraries
I'd recommend a solution with a account table containing three fields:
birthday, which is of Postgres type date.
timezone, of Postgres type text. Here you'd store something like Europe/Amsterdam, with the important part is that it's something Postgres and your date libraries can all recognize as a time zone.
last_birthday_wish_sent_at of type timestamptz (shorthand for timestamp with time zone, which stores everything internally as UTC).
I've decoupled the birthday date from its timezone because remember that a user's birthday is always the same day anywhere in the world, even if they move around. So if my birthday is August 11th in Amsterdam, it's still August 11th if I move to San Francisco. Storing these components separately would allow you to reconfigure their timezone if they move.
I'd run a cron on the 0th minute of each hour that ran logic something like this (pseudocode, sorry):
for timezone in all timezones:
if > 12 PM in timezone:
for account in accounts in timezone:
if birthday <= today AND (last_birthday_wish_sent_at IS NULL OR last_birthday_wish_sent_at < now() - '1 year):
send birthday wish
set last_birthday_wish_sent_at = now()
The purpose of last_birthday_wish_sent_at is so that you can write an algorithm that's a bit dumber and more resilient (i.e. birthday wishes still get sent even if the cron fails one hour), but still make sure to never double-send a birthday wish for any given year.
It might also be safer to model this as a separate table where you track every birthday wish you've ever sent and the user and year you sent it for. This eliminates any potential for time bugs across year boundaries.
You'd want to model the account selection and filtering in the pseudocode above as SQL so that you're not returning result sets larger than necessary. Something like:
SELECT *
FROM account
WHERE timezone IN ('Europe/Amsterdam', ...)
-- note: actual date comparison a little more complicated than this
-- because you should make sure to compare the month and day components
-- only (probably with the `EXTRACT` function)
AND birthday <= NOW()
AND (
last_birthday_wish_sent IS NULL
OR last_birthday_wish_sent < NOW() - '1 year'::interval
);
And make sure there's appropriate indexes on timezone, birthday, and last_birthday_wish_sent.
You could also tighten up the logic around time zone checks: it's always turning 12 PM somewhere, but it's perfectly predictable as to where that's happening so it's not necessary to check every time zone every time. You could also potentially push this into Postgres and get the whole selection logic packaged up into a single query.

Storing/Calculating date/time with JS

What is the best practice for saving some time informations in JS?
In my case I want to save the datetime as a user account is created. 36h after creating the account I want to show a message to the user.
Right now I'm saving a timestamp with new Date().getTime();. But maybe it is possible to calculate for some events just with new Date()?
This is how I do it, but it feels not very elegant - especially for complex calculations.
var currentTime = new Date().getTime();
if ( (timeRegistrated + 1000 * 60 * 60 * 36 - currentTime) >= 0 ) {
console.log('36h are over...');
}
I think I have to use some library for complex calculations (like current age of user or how many months between two dates)... But still the basic question: Which type of date-data should be used for the DB?
Moment.js has a fromNow function. It's way easier.
http://momentjs.com/
moment("20111031", "YYYYMMDD").fromNow();

Parse Clouod Code Check If Date Is Today

In my app i want a feature where the user can update their status but i want them to only be able to update it once every 24 hours. Basically i want to take the updatedAt field from parse and check if the change was today in Cloud Code.
I am not very familiar with javascript but her's what i've tried:
https://www.parse.com/questions/compare-date-and-createdat-to-figure-out-the-difference-in-days
How to compare 2 Date fields in Parse Cloud?
I couldn't get to a solution that would basically tell me (beforeSave) if the date is today and allow the user to save/update the field if it isn't.
An example of what i want is WhatsApp that only allowed changing the last seen status on/off once every 24 hours. Also Viber has this feature.
Thanks.
Parse.com supports moment.js
var updatedAt = ... ; // Get updatedAt value of your object
var now = moment();
if (now.diff(updatedAt, 'hours') >= 24) {
// Last update was more than 24 hours ago
}

Using timezones with moment.js fromNow() or from()

I want to show users how long has been elapsed since they performed an action.
The date+time of the action happening is stored on the server, in the server's timezone. That's what's causing the trouble, since if the user's computer's timezone is 12 hours ahead of the server's timezone, then if the user adds something right now, moment.js will show '12 hours ago' as the output of fromNow() rather than just now.
To try to solve this, I'm trying the following method:
var actionTime = moment( action.timeStamp);//time of when user performed action
var serverTime = moment().zone('-07:00'); //current server time
console.debug( serverTime);//outputs Wed Sep 11 2013 15:19:51 GMT-0700
var timeAgo = serverTime.from( actionTime);
But despite of all this, timeAgo still shows the difference between the client's timezone and the server's timezone (i.e showing '12 hours ago' instead of 'now');
Anyone know how to fix this or what I'm doing wrong?
Ideally, you would want to pass a UTC timestamp from your server to the client. That doesn't mean you have to switch your whole server over to UTC, it just means that you would convert from the time in your database to UTC on the server before sending it over the web. Sure, it would be even better if you actually stored times in UTC, but you said you aren't in a position to make that sort of change right now. But let's just work off the assumption that you can't change anything at all on the server.
We'll also assume that your server is fixed to the UTC-07:00 offset. In real life, this would only be true for places like Arizona that don't follow daylight saving time. So if you are in Los Angeles and are in Pacific Time, then some of your data is based on UTC-07:00, but some of it is based on UTC-08:00. That requires a lot more work if you want to do it in JavaScript.
Let's also assume that the input is already a string in ISO8601 format. (If it's not, then let me know and I will adjust this code.)
var s = "2013-09-11 18:00:00"; // from action.timeStamp
var actionTime = moment(s + "-07:00", "YYYY-MM-DD HH:mm:ssZ");
var timeAgo = actionTime.fromNow();
The reason your other code didn't work is because in the first line, you are affected by the time zone of the browser. The zone setter in the second line just changes the zone for formatting, not changing the actual moment in time.
Also, when you dump a moment to the console for debugging, make sure you format it for output. Otherwise you are just looking at its internal property values, which may or may not make sense directly.
I have solved it in a different way, maybe this option was not possible back when the question was asked, but might be easier now.
I used moment-timezone.js (which requires moment.js 2.6.0+).
I set the default timezone to my server's timezone like this:
moment.tz.setDefault("America/New_York"); // "America/New_York" in my case
and then just use it normally. fromNow() will use the timezone in the client to calculate the time that has passed since that moment.
moment(myDatetime).fromNow();
i had the same issue and used the above comments to modify my code. I did the following to get it resolved:
transform(value: string) {
var time = moment(value).utc();
return moment(time, "YYYYMMDD").fromNow();
}
I was missing the .utc() to convert it before I applied the .fromNow()
Things to note this is being used within a Pipe for Ionic 3 and the above code is from the pipe logic.

JavaScript Addition Date Functions

I don't really know too much about core JavaScript, just a dot of jQuery. But I know jQuery is not necessary for what I need here:
I want to use the getdate function to find out the server's day of the week. Then add a bunch of clauses like:
if its Monday add 6 to the date and return the date in MM/DD/YYYY form.
if its Tuesday add 5 to the date and return the date in MM/DD/YYYY form.
if its Wednesday add 4 to the date and return the date in MM/DD/YYYY form.
and so on until Sunday when it will add 0.
So lets say todays Monday, it will return 1/8/2012
And in real dates today's Sunday so it will really return 1/1/2012
Then I just want to call a document.write function to write the MM/DD/YYYY it returns into my HTML document.
Can anybody help me? I can clarify if you need me to...
getDay() returns the day of the week, Sunday = 0, Monday = 1, etc, etc.
So say today was Monday getDay() would return 1, which means daysToAdd would be 5.
Once we know how many days we want to add we can create a new date and add those days. We do this by getting today in milliseconds and then adding the number of days (daysToAdd) in milliseconds.
We convert days to milliseconds by multiplying by 24*60*60*1000 which is the number of milliseconds in a day.
I add 1 to the month because JavaScript returns 0 based month, but for display purposes we want to format it so that January for example is 1 not zero.
function getEndOfWeek() {
var today = new Date();
var weekDay = today.getDay();
// if you want the week to start on Monday instead of Sunday uncomment the code below
//weekDay -= 1;
//if(weekDay < 0) {
// weekDay += 7;
//}
var daysToAdd = 6 - weekDay;
var newDate = new Date(today.getTime() + daysToAdd *24*60*60*1000);
var month = newDate.getMonth() + 1;
var day = newDate.getDate();
var year = newDate.getFullYear();
var formatedDate = month + "/" + day + "/" + year;
return formatedDate;
}
You could implement in your code like so, JavaScript:
$(function() {
$("#TheDate").html(getEndOfWeek());
});
Your HTML would be something like this:
The week ends on <span id="TheDate"></span>.
You can find the jsFiddle here: jsFiddle
If you want to adjust the weekday so that you consider Monday the start of the week instead of Sunday you can do the following after you get the weekDay:
weekDay -= 1;
if(weekDay < 0) {
weekDay += 7;
}
var day = 1000*60*60*24
, nextSunday = new Date(+new Date() + day*(7-((0|(+new Date()/day)%7-3)||7)));
alert(
(101+nextSunday.getMonth()).toString().substr(1) + '/' +
(100+nextSunday.getDate()).toString().substr(1) + '/' +
nextSunday.getFullYear()
)
As fas as adding dates in JavaScipt my "DateExtensions" library does this well enough, I think. You can get it here:
http://depressedpress.com/javascript-extensions/dp_dateextensions/
Once refenced you can call "add()" as a method for any valid date and pass it any of many date parts (second, minutes, days, hours, etc). So assuming "curDate" is a valid JavaScript date object you can add 5 days like this:
newDate = curDate.add(5, "days");
Using a negative value will subtract:
newDate = curDate.add(-5, "days");
Once you get the date you want you can the use the library's dateFormat() method to display it like so:
curDate.dateFormat("MM/DD/YYYY");
There's full documentation at the link.
Integer Values for Day of Week
As for getting the integer value you want, it's actually easier that it looks (and you don't need an "if" just some math). The getDay() method of date returns the day of week with Sunday as "0" and Saturday as "6". So the week, from Sunday, would normally be:
0,1,2,3,4,5,6
First, you want to reverse that scale. That's easily done via subtraction by taking 7 (to total number of members of the set) from the value. This gives you this scale:
-7,-6,-5,-4,-3,-2,-1
We're getting closer. You want the first value to be zero as well. The simplest way (I think) to do this is to get the modulus (remainder) of the value by the total number of members. All this basically does is make "-7" a zero and leave the rest alone giving us this:
0,-6,-5,-4,-3,-2,-1
Almost done. Finally you don't want negative numbers so you need to use the Math.abs() method to eliminate the sign (get the absolute value) leaving us with our desired result:
0,6,5,4,3,2,1
For all the talk the acutual code is pretty compact:
Math.abs((cnt-7)%7)
Wrapping this into the original example gives us:
newDate = curDate.add(Math.abs((curDate.getDay()-7)%7), "days");
Server Vs Client
However take nnnnnn's comment to heart: in JavaScript the getDate() function gets the current date/time of the machine that it's running on - in the case of a web page that's the client, not the server.
If you actually meant the client time them you're set and done. If you really need the server time however that's annoying-to-impossible. If you own the server then it's actually not to hard to set up a rule that includes the current server in a cookie withing each fufilled request (you could then use my cookie library, also at the site above, to access the information!)
It's messier but depending on the server you might also be able to create an old-school server-side include that adds a bit of JavaScript to each page (preferably as a marked replace in the header) that hard-codes the date as a global variable.
You might also create a web service that returns the current server time but the client-overhead for that is insane compared to the data being delivered.
If the server's NOT yours (and you can't get the owner to provide the above) then the only real potential option is to do a straight http call and examine the HTTP "Date" header. Again however the overhead on this is immense compared to the return but it's really the only way. Any system like this would have to be very flexible however as any particular server might not return the date header or might not return it correctly.
Even if it does work understand that you might still not be getting the "server" time - or at least not the server you want. In a tiered architecture, for example an application server might render then page and hand it to a web server to return - you'd be getting the web server time, not the app server. Any number of appliances might also rewrite the headers (for example it's common to use dedicated SSL appliances to offload all the encryption work - these often re-write the headers themselves).
Sorry to get overly technical - JavaScript is definately one area where there's unfortunately rarely a "simple question". ;^)
Good Luck!

Categories

Resources