Find the oldest date in a list of dates - javascript

I need a help in coming up with function in JavaScript. The function should be able to find the oldest date from the list of dates in this format yyyy-mm-dd hh:mm:ss. So the function would receive a text and among the lines it should find the oldest date entry and select text associated with that date.
Also if there is Java solution for this problem that could work to and I will use something to include Java inside JavaScript.

This'd work, assuming datelist is the string and that each date is on its own line:
var oldest = (function() {var o = ":", c, a=datelist.split(/\r?\n/); while(c=a.shift()) o = o < c ? o : c; return o;})();
Breaking that down, here's how it works: It's basically creating a function, running it, then getting its return value. The function is like so:
var o = ":",
// ":" comes after "9" in the character map, so it will be greater than any date
c, a = datelist.split(/\r?\n/);
// split on newlines, accomodating both \r and `\r\n` options.
while(c = a.shift()) {
// basically loop through each date
o = o < c ? o : c;
// if the current oldest date is older than the one we're looking at, keep the old one
// otherwise the new date is older so should be kept
}
return o;
// return the result

Here is how you would do it...
Iterate over the dates as an array, turning them into Unix epochs.
Find the oldest with Math.min.apply(Math, arrayOfDates) or better yet Math.min(...arrayOfDates).

You can convert all the date strings to Date objects, and then sort your list numerically and get the first item. Alternatively you can just apply Math.min on it to get the lowest value, if you don't need a sorted list.
var minDate = Math.min.apply(null, datestrings.map(Date));
Or, as your format does have leading zeroes, a simple string sort will do the same. To only search for a minimum string, you can use this:
var min = datestrings.reduce(function(min, cur) {
return cur < min ? cur : min;
});

A Wibbly-wobbly dollarsy-wollarsy example using jquery:
$("body").append($("<div>").attr("id", "q")); //some gratuitous jquery
var timelist = "2012-03-03 10:14:21 \r\n 2012-05-15 21:21:12\r\n 2012-07-01 10:19:19\r\n2012-02-11 21:21:12";
var datelist = timelist.split("\r\n");
var oldest = ":";
$.each(datelist, function (a) {
var trimmedThis = $.trim(this);
if (trimmedThis < latest) oldest = trimmedThis;
});
$("#q").text(oldest); //just to beef up the $ count

Related

Comparing '==' in an IF statement is not working Google Sheets script

The objective is to compare ColA in the Orders sheet with ColF in the Ordered Items sheet, if they match grab the email from ColB.
The script outputs no errors, but it doesn't match the highlighted cells in either sheet.
(note: the items are automatically added by an app, so the formatting of the cells are default and need to keep it that way as I'm using the last 6 digits as the order reff eg; 49.263Z)
Orders sheet
Ordered Items sheet
function getEmailFromOrderedItemToOrders(){
var orders = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Orders');
var lr = getLastRow(orders, "A1:G");
Logger.log(lr); //LastRow index
//Get last 'OrderID (Paid at)' value from 'Orders' sheet
var orderIdCol = 1;
var orderId = orders.getRange(lr, orderIdCol).getValue();
Logger.log(orderId); //LastRow 'orderId' value
//Match 'orderId' to 'orderId' in 'Ordered Items' and return col 1
var items = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Ordered Items');
var itemsData = items.getDataRange().getValues();
Logger.log(itemsData[0][1]); //'Purchase Email' col
Logger.log(itemsData[0][5]); //'Paid at' col
for(var i = 0; i<itemsData.length;i++){
if(itemsData[i][5] == orderId){ //Issue here: not comparing values as a match
var email = itemsData[i][1];
Logger.log(email); //Does not print
return i+1;
}
}
}
In javascript when you compare two new Date, you will be getting the value as false.
Reason is when you have two dates, its basically two different objects. So One object is not equal to another object when you use == or ===. So the simple and better way is converting the date to a number using .getTime() that will return how many milliseconds passed from that date and 00:00:00 of Jan 1, 1970.
Sample code snippet
console.log(new Date() === new Date())
console.log(new Date().getTime() === new Date().getTime())
This can be simply solved by using a Sheets Formula which. What you would do is:
=INDEX( 'Ordered Items!B:B', MATCH(A2, 'Ordered Items!:F:F,0) )
The formula basically says:
Return the Email Column
Find the Index (# of the row) where the value of A2 is in column Ordered Items F:F
See here for a tutorial on it: https://www.youtube.com/watch?v=9sLWDjAEuyc

Converting a string (150000) to time ( hh:mm:ss) in javascript

I am new to JS. Can anybody tell me whether is it possible to convert a string ( eg: "140000") to time (eg: 14:00:00) in Javascript.
You can do this:
Split your text into an array using the split method.
Map over your array and replace every item that has the index can be divided by to with the item + : using the map method.
Join your array to be string again using the join method.
Remove the last : from your result.
let convertToTime = str => str
.split("")
.map((item, index) => (index % 2 != 0) ? item + ':' : item)
.join("")
.slice(0, -1);
console.log(convertToTime("140000")); // 14:00:00
console.log(convertToTime("173003")); // 17:30:03
console.log(convertToTime("225510")); // 22:55:10
console.log(convertToTime("010201")); // 01:02:01
That's a bit tricky, because well... there is no Time object in Javascript.
There is only a Date object, although the name is kind of misleading, because the Date object contains both "Date" and "Time". There is a reason behind this seemingly confusing convention. I'm not going to go into too long of a detail, but to put it shortly, referencing "Time" is unreliable (to human brain).
For that, I'll just recommend reading this answer which explains it quite brilliantly.
Either way, this simple function will do the trick.
toDate(what){}
Upon sucessful string of time conversion, return a newly created Date object. Otherwise return -1. (or you could throw an Exception instead, up to you really)
var str = '143025';
function toDate(what){ // turns string into Date() object
var result;
if (what.length === 6) { // must be in HH:MM:SS length
var timearr = what.match(/.{1,2}/g); // splits time to HH:MM:SS array
if (timearr[0] <= 24 && timearr[1] <= 60 && timearr[2] <= 60){
return new Date('01 January 0001 ' + timearr[0] + ':'+
timearr[1] + ':' + timearr[2] + ' GMT'); // valid time format
}
}
return -1;
}
var mytime = toDate(str);
console.log(mytime.toUTCString());
Note, Date by itself is only expression of serialized numbers, if you want to return the time as result, you need to use the .toString or .toUTCString method from the Date.prototype object.

Get most current data from Array JavaScript

I have a SP2010 list which contains a column with dates. (Date created).
I pull these using Spservices which comes in the following format:YYYY.MM.DD 00:00.
In the main function which reads the list I split the date so all that remains is YYYY.MM.DD.
dateAdded = ($(this).attr("ows_DatumActualiteit")).split(" ")[0];
The dates are then pushed in to an array for later filtering.
function selectMostRecentAct(datesIn){
var dateArray = [];
dateArray.push(datesIn);
for (var i = 0; i < dateArray.length; i++) {
console.log(dateArray[i]); //spits out all the dates in the array.
};
I want to select the most recent date in this array. How can I achieve this?
This question seems similar to yours:
What is the elegant way to get the latest date from array of objects in client side?
An alternative would be to loop through the whole array and compare the dates. As far as I know, you can use the <, >, == operators with dates.
dateArray.forEach((e) => {
if (e > latestDate)
latestDate = e;
});
console.log('Latest date is: ' + latestDate);
You need to sort the values then take the first element.
I'm assuming the format of your dates, but new Date is very lenient and should accept most reasonable inputs.
const dates = [
"2018-03-01T10:30:12.000Z",
"2018-03-01T12:11:49.000Z",
"2018-03-12T15:54:49.000Z",
"2018-03-09T19:12:49.000Z",
"2018-03-03T01:41:49.000Z",
];
const selectMostRecent = dates =>
dates.sort((a, b) => new Date(b) - new Date(a))[0];
console.log(selectMostRecent(dates));
Sort wants a comparison function that returns a value, either positive, negative or zero. When you perform arithmetic on a date value it is converted to epoch time (e.g. 1522096404277, milliseconds since 01/01/1970), and then subtracting these gives us the signed value we desire.
For example,
2018-03-09T19:12:49.000Z returns 1520622769000
2018-03-03T01:41:49.000Z returns 1520041309000
And when we do 2018-03-09T19:12:49.000Z - 2018-03-03T01:41:49.000Z (but those are coerced to numbers as described above) we get 581460000, meaning that the first date is sorted above the latter one.
Maybe something like this:
dateArray
.map(d => new Date(d.replace(/\./g, "-"))) // ISO format
.sort((a, b) => b - a) // Newest to oldest, probably
[0] // First!
This uses a reusable function for max; it should work for any values that you can compare with >. Note that it requires you to set a minimum value. For strings, "" (the empty string) seems appropriate. For numbers, you could use -Infinity, although that case is already covered by Math.max. For actual dates (not these dates formatted as strings), you can choose any date that would be well before any conceivable values, perhaps something like new Date(-1e15).
const max = (min) => vals => vals.reduce((curr, val) => val > curr ? val : curr, min)
const maxDate = max('')
console.log(
maxDate(['2014.07.23', '2014.08.29', '2007.03.25', '2017.09.30', '2008.02.29'])
)

Find missing quarters in time series

I am trying to see how could I fill the missing financial quarters of a time series like this in Javascript:
["2012-Q2","2012-Q4","2013-Q4","2014-Q1","2014-Q2","2014-Q3",
"2014-Q4","2015-Q1","2015-Q2","2015-Q3","2015-Q4","2016-Q1",
"2016-Q2","2016-Q3","2016-Q4","2017-Q1","2017-Q2","2017-Q3",
"2017-Q4","2018-Q1"]
I would like somehow to get a time series with the missing elements i.e. for each year I should see 4 "dates".
I don't mind ignoring the first quarter before the first element "2012-Q2" and the last 3 quarters after the last element "2018-Q1".
I know moment.js has functions like quarter() or fquarter() (via a plugin), but I am looking for something closer to the other way around. I already have the quarters (as date-strings), and I have to parse them as date objects.
I need to fill the "quarter holes" in between those input string values.
In my case I probably need to parse first those date-strings in that custom format to make them something moment could understand, but I am a bit lost. In here https://momentjs.com/docs/#/parsing/string-format/ a potential format could involve Y for years and Q for quarters, but I am not sure how to escape the literal Q inside every input date-string of that array?
Also assuming I could somehow parse all those date strings into moment objects, then I am not sure how that could help in filling the holes?
I can not find a pure javascript solution involving date types.
Another approach could be to parse those date-strings and get the year and the quarter number using substring and then manually filling the holes checking year/quarter pairs, is there anything simpler than this?
Assuming that you want a full list of quarters between the first one of your input array until the last one, you can:
parse with moment the first and the last element of your array, using moment(String, String) with 'YYYY[-Q]Q' as format parameter, see Escaping charaters section of the docs.
loop from start to end using isSameOrBefore (or other query functions) adding 1 quarter on each iteration (add(1, 'Q'))
Here a live sample:
var quarters = ["2012-Q2","2012-Q4","2013-Q4","2014-Q1","2014-Q2","2014-Q3",
"2014-Q4","2015-Q1","2015-Q2","2015-Q3","2015-Q4","2016-Q1",
"2016-Q2","2016-Q3","2016-Q4","2017-Q1","2017-Q2","2017-Q3",
"2017-Q4","2018-Q1"];
var format = 'YYYY[-Q]Q';
var start = moment(quarters[0], format);
var end = moment(quarters[quarters.length-1], format);
var results = [];
while( start.isSameOrBefore(end) ){
results.push(start.format(format));
start.add(1, 'Q');
}
console.log(results);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.20.1/moment.min.js"></script>
Why not just make a function that returns the quarters from a particular range?
function getQuarters(startYear, endYear){
var times = [];
for(var i = startYear; i <= endYear; i++){
times.push(i + "-Q1");
times.push(i + "-Q2");
times.push(i + "-Q3");
times.push(i + "-Q4");
}
return times;
}
Calling:
getQuarters(2017,2017);
Returns:
["2017-Q1", "2017-Q2", "2017-Q3", "2017-Q4"]
Assuming you want to get an array with the missing values, you could take a start quarter and cehck against the given data for either pushing the quartal or incremet the index of the array.
function incQ(time) {
time[1]++;
if (time[1] === 5) {
time[0]++;
time[1] = 1;
}
}
var quarters = ["2012-Q2", "2012-Q4", "2013-Q4", "2014-Q1", "2014-Q2", "2014-Q3", "2014-Q4", "2015-Q1", "2015-Q2", "2015-Q3", "2015-Q4", "2016-Q1", "2016-Q2", "2016-Q3", "2016-Q4", "2017-Q1", "2017-Q2", "2017-Q3", "2017-Q4", "2018-Q1"],
actual = quarters[0].split('-Q'),
missing = [],
i = 0;
while (i < quarters.length) {
if (actual.join('-Q') !== quarters[i]) {
missing.push(actual.join('-Q'));
} else {
i++;
}
incQ(actual);
}
console.log(missing);

Read a file with latest Date from a folder using JQuery

I already have a folder, with the files in it with names below in a specific format i.e. MODEL_RELEASEDATE
File names in the folder named Smartphone
SmartphoneA_11122012
SmartphoneA_01022013
SmartphoneA_09102013
SmartphoneA_10072012
SmartphoneA_12042012
**SmartphoneB_08282013**
SmartphoneB_04152013
SmartphoneB_08282012
SmartphoneB_01062013
.
.
.
.
and so on
I want to write a jquery code where I can use a specific keyword from format, from above list, I will pass the value SmartphoneA and I should be able to read the file with the latest release date. Same as in case when I pass the keyword SmartphoneB.
If I pass k/w SmartphoneB, result should be served from file highlighted above, i.e. SmartphoneB_08282013
my current code reads the file name only with specific k/w. I have few alterations to be made.
<script type="text/javascript" src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script type="text/javascript">
var metaKeywords=$('meta[name=keywords]').attr("content");//this utility works based upon the keywords on the pages.
var reqdKeyword = new Array();
reqdKeyword = metaKeywords.split(",");
var randKeyword = reqdKeyword[Math.floor(Math.random() * reqdKeyword.length)];
var cdnUrl = "http://abc.com/xyz/mobiles/";
var jsnUrl = ".json?callback=showDetail";
var finalUrl= cdnUrl.concat(randKeyword.trim()).concat(jsnUrl);
/*
Rest of the code goes here
*/
</script>
The cool thing about dates is that you can easily sort them if you have the date in "descending" order (i.e., year month day hour second). Using that, we can go through your files to grab just the ones that start with the right prefix, then easily grab the latest one:
var filenames = [
'SmartphoneA_11122012',
'SmartphoneA_01022013',
'SmartphoneA_09102013',
'SmartphoneA_10072012',
'SmartphoneA_12042012',
'SmartphoneB_08282013',
'SmartphoneB_04152013',
'SmartphoneB_08282012',
'SmartphoneB_01062013'
],
whichPhone = 'SmartphoneB', // Dummy value, this would come from user interaction or whatever
possibleFiles = [];
// This goes through your list of filenames and picks out just the ones that match `whichPhone`, then puts them into another array containing a "cleaned-up" date and some other metadata-esque stuff
for (var i = 0, j = filenames.length; i < j; i++) {
var filename = filenames[i];
if (filename.indexOf(whichPhone) > -1) {
possibleFiles.push({
index: i,
filename: filename,
date: parseInt(filename.split('_')[1].replace(/(\d{2})(\d{2})(\d{4})/, function(match, month, day, year) {
return year + month + day;
}), 10)
});
}
}
// Now we go through the `possibleFiles` and figure out which one has the latest date
var latestFileDate = 0,
theActualFilenameYouWantFinally;
for (var i = 0, j = possibleFiles.length; i < j; i++) {
var possibleFile = possibleFiles[i];
if (possibleFile.date > latestFileDate) {
latestFileDate = possibleFile.date;
theActualFilenameYouWantFinally = filenames[possibleFile.index];
}
}
// And, finally, your result
console.log(theActualFilenameYouWantFinally);
EDIT: I didn't use jQuery for this answer because meh, you don't really need jQuery for things like this. Don't get me wrong, John Resig is brilliant, and I use jQuery in almost everything, but for loops are damned fast and easy to work with, and stuff like this isn't really jQuery's strong suit anyhow.
You will need a server-side code to return you a list of URIs (file names), then you can write JavaScript code to parse it (but in this case it is probably better if your server-side code will return the right name right away based on query string). In the worst case scenario you can place a dir.txt file on the server which will be listing all the files in that folder and e.g. run cron job to update it as needed.
jQuery will have no way to list remote files on the server unless your server supports it in one way or another.
Update
Once you have the file you need:
a) tokenize it into an array, e.g. like this
var names = dir.split("\n");
b) leave only strings starting with keyword and cut keyword off
names = $(names).map(function(n,i) {
return (n.indexOf(keyword) == 0) ? n.split('_')[1] : null;
}).get();
now you have an array like this ['11122012', '01022013', ...]
c) find max date in this array
var dateNum = Math.max.apply( null,
$.map(names,function(n,i){ return parseInt(
n.replace(/(\d{2})(\d{2})(\d{4})/, function(match, month, day, year) {
return year + month + day;
}))
}) );
var maxDate = dateNum.toString().replace(/(\d{4})(\d{2})(\d{2})/,
function (match, year, month, day) { return month + day + year; }
);
var fileName = keyword + "_" + maxDate;
voila, your fileName contains the name with max date.
There are other ways of doing it, e.g. really parsing the date into Date object. Also, you can simply iterate your files once, without array mapping and Math.max() iterator. As the amount of code wins over speed here, to find the optimal one depends on where you could re-use its bits and pieces without compromising maintainability.
http://jsfiddle.net/Exceeder/VLB2E/

Categories

Resources