d3.min.js gives Uncaught TypeError: n.apply is not a function - date

I'm trying to split a datetime in two variables cx (should be the day in the year) and cy (should be the hour+minute/60) according to:
<!-- date format of d.date: 24-8-2016 9:47:38-->
var parseDayinYearFormat = d3.time.format('%j').parse;
var parseHourFormat = d3.time.format('%H').parse;
var parseMinuteFormat = d3.time.format('%M').parse;
<!-- add the objects-->
var circles = svg.selectAll("circle")
.data(data)
.enter()
.append("circle");
var circleAttributes = circles
.attr("cx", function (d) { return +parseDayinYearFormat(d.date); })
.attr("cy", function (d) { return +parseHourFormat(d.date)+(parseMinuteFormat(d.date)/60); })
.attr("r", function (d) { return 20.0/(9-d.total); })
.attr("class", function (d) {if (d.w>d.total-d.w) {return "cr"} else { return "cb" }});
But d3 isn't playing nice: cx and cy become a NaN and d3 is giving the error Uncaught TypeError: n.apply is not a function
Please help.

You need to parse the entire string with a single format object. You can’t parse the string with a sequence of parsings.
Using the d3 version 3.x documentation I came up with the following, which works on your example.
var datestring = '24-8-2016 9:47:38';
var format = d3.time.format('%-d-%-m-%Y %-H:%-M:%-S');
console.log(format.parse(datestring))
// "2016-08-24T13:47:38.000Z" // (my time zone is UTC-4)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Note that because your example 24-8-2016 9:47:38 has many fields that show no zero-padding, I use a dash between the % and the specifier, i.e., %-d, to tell d3 that there may be no zero in the beginning.
Also note that in your example, there is no way 24 is a day-of-year, which is between 1 and 366: 24 is clearly just a day of the month, right?
However, it appears from your code snippet that you just want to extract the day and hour and minute from a string. For this simple purpose, d3.time.format might be overkill, since it gives you a Date object, which then you have to parse to extract the day/hour/minute. Consider using a regular expression for this task.

Related

Coffeescript if condition for date

This is my 1st mini project using coffeescript dcaf.
Im currently doing some function in coffeescript, my roadblock is i cant compare 2 dates on if statement. Any thoughts?
In JavaScript (and also in CoffeeScript) the comparison operators (<,<=,==,>=,>,!=) are overloaded for the Date object.
Hence you can use something like this (in plain JavaScript):
var d1 = new Date();
var d2 = new Date();
if (d1 < d2) {
console.log("D1 is strictly before D2");
}
or like this (in CoffeeScript):
d1 = new Date()
d2 = new Date()
if d1 < d2
console.log "D1 is strictly before D2"
In both cases the underlying implementation is equivalent to a numeric comparison of the "epoch time" representation of the Date object - number of milliseconds since midnight (00:00:00) 1 January 1970 UTC - the same value returned by the getTime() method. So d1.getTime() < d2.getTime() would be an alternative way to express that comparison if you want to be more explicit about what is being compared.

Problem with understanding date formats in googleScripts

I made a few functions with GoogleSheets using AppsScripts for simple task a few times in previous years. I always had problems when taking dates from cells/ranges and processing them, but somehow alwaays found a workaround, so that I did not have to deal with it. Well, this time I can not find a workaround, so I will try to explain my problems with the following code:
function getDates(){
var s = SpreadsheetApp.getActiveSpreadsheet();
var sht = s.getSheetByName('Dates');
var date = sht.getRange(2,1).getValues();
Logger.log(date[0][0]); //output is Tue Jun 08 18:00:00 GMT-04:00 2021
var datumFilter= Utilities.formatDate(date[0][0], "GMT+1", "dd/mm/yy");
Logger.log(datumFilter); //output is 08/00/21
var outrng = sht.getRange(25,1);
outrng.setValue(date);
}
The first targeted cell ('var date') has a value of "9.6.21" in the spreadsheet. The cell is formatted as a date and it opens a calendar when double-clicked. When I set the new cells values (with 'outrng.setValue(date);'), the result is OK, with the same date as in the original cell.
But I do not need to simply transfer the values, I want to implement them in some loops and I have no idea how to simply get the date in the same format or at least the same date in the script as it is in the cell. As you can see from the logger, the values there are different. A simple d/m/yy format would be sufficient.
My spreadsheet settings are set to my local time (Slovenia, GMT+1).
I am guessing that I am missing some basics here. I have spent many hours trying to understand it, so any help is highly appreciated!
Cooper already answered all your questions in the comment. I'd like to add on and show you an example on what it would like and add some modifications.
Code:
function getDates() {
var s = SpreadsheetApp.getActiveSpreadsheet();
var sht = s.getSheetByName('Dates');
// get last row of the sheet
var lastRow = sht.getLastRow();
// get your sheet's timezone
var timezone = SpreadsheetApp.getActive().getSpreadsheetTimeZone();
var output = [];
// getValues is mostly used for multiple cells returning a 2D array
// use getValue for single cells to return its actual value
// but since function name is getDates, I assume column A is all dates
// so we fetch the whole column (A2:A[lastRow]) except the header
var dates = sht.getRange("A2:A" + lastRow).getValues();
// for each date on that column, we format the date to d/M/yy
// m/mm = minute
// M/MM = month
dates.forEach(function ([date]){
Logger.log(date);
var datumFilter= Utilities.formatDate(new Date(date), timezone, "d/M/yy");
Logger.log(datumFilter);
// collect all dates in an array
output.push([datumFilter]);
});
// assign all the dates in the array onto range B2:B
sht.getRange(2, 2, output.length, 1).setValues(output);
}
Sample data:
Logs:
Output:
Note:
The output on sheets is not equal to logs due to the formatting of my sheet.

Comparing date by combining it

Im just wondering. is it ok to combine years,month, and day of two date and make a comparison based on the combination.
eg:
Date A: 12th-January-2019
Date B: 24th-December-2018
Based on the above date, i could combine the year,month, and day as follow:
Date A: 20190112
Date B: 20181224
So based on the numbers, i could do logic like below to compare which date comes first:
if(Date A > Date B) {
output("Date A is the latest")
}
i would like to implement this method just to compare which is the latest date.
are there any problem of doing so.
java.time
Since you are using Java, I suggest that you take advantage of java.time, the modern Java date and time API.
String[] dateStringsFromDatabase = {
"2018/12/19",
"2017-02-01",
"2018.03.04",
"25-12-2016", // reversed
"2019\\09\\12",
"2014:03:01"
};
List<LocalDate> parsedDates = new ArrayList<>(dateStringsFromDatabase.length);
for (String dateString : dateStringsFromDatabase) {
// No matter which delimiter is used, replace it with a hyphen
String text = dateString.replaceAll("\\W", "-");
try {
parsedDates.add(LocalDate.parse(text));
} catch (DateTimeParseException dtpe) {
System.out.println(dateString + " not parsed: " + dtpe.getMessage());
}
}
Output:
25-12-2016 not parsed: Text '25-12-2016' could not be parsed at index 0
What this approach buys you is validation of the dates even though they come with all different delimiters. Especially in this situation I believe that you should want to validate that your strings are within the expected variations. Otherwise you risk that a date with the numbers reversed ends up as a date in year 2512, for example. You want to catch that before it happens.
Example of comparing which comes first:
for (int i = 1; i < parsedDates.size(); i++) {
LocalDate dateA = parsedDates.get(i - 1);
LocalDate dateB = parsedDates.get(i);
if (dateA.isAfter(dateB)) {
System.out.format("%s is later than %s%n", dateA, dateB);
}
}
Output:
2018-12-19 is later than 2017-02-01
2019-09-12 is later than 2014-03-01
Link: Oracle tutorial: Date Time explaining how to use java.time.

Formatting a Time value on Ionic 3

I need to find the way to format a time, I tried with angular pipe, but this works with date type values.
I need to be able to remove the seconds to values of the hours shown, example:
1:45:00 change to 1:45 pm or 1:45 p.m. M.
Assuming your date is a instance of Date you can use the built in angular date pipe with the predefined format shortTime or a custom format:
<p> {{date | date:'shortTime'}} </p>
<p> {{date | date:'hh:mm'}} </p>
shortTime is equivalent to 'h:mm a' and will produce results like 9:03 AM.
The custom format 'hh:mm' will produce results like 09:03.
If your date is just a string you could use the built in slice pipe to remove the parts you want to get rid of:
<p> {{"1:45:00" | slice:0:4}} </p>
Which will output 1:45.
Also see this Stackblitz for the different options.
Anyway I'd reccomend using real Date objects or Moment.js objects over bare strings, it makes things a lot easier, especially once you start comparing dates or calculating with dates.
Use Moment.js .here you can convert to any time format
1 - Install via NPM:
npm install moment -S
2 - Import in your Typescript file:
import moment from 'moment';
3 - Use in your Typescript file:
let dateString = "22-04-2017"; //whatever date string u have
let dateObject = moment(dateString, "DD-MM-YYYY").toDate();
If this is format is always the case you can manipulate the string with JavaScript/TypeScript.
myTime = '1:45:00'
showTime() {
var result =
this.myTime.substring(
0, (this.myTime.length - 3) )+ ' pm';
console.log(result);
}
If you have more complicated cases You could use a library like Momentjs.
https://momentjs.com/
This is where you can find what you need in the docs.
https://momentjs.com/docs/#/parsing/string-format/
you can use a custom pipe
transform(timeString: string) {
let time = timeString.slice(0, 5);
let current_hour = timeString.slice(0, 2);
if (parseInt(current_hour) > 12) {
time = time + " PM";
} else {
time = time + " AM";
}
return time;
}

What is the most efficient way to convert an eight digit number to a date?

I am using ColdFusion 9.0.1 and some database that I cannot change.
I am accessing a database that stores a date as an eight digit numeric with zero decimal places like this:
YYYYMMDD
I need to be able to read the date, add and subtract days from a date, and create new dates. I am looking for a ColdFusion solution to efficiently (not much code) to convert the date to our standard format, which is
MM/DD/YYYY
And then convert it back into the database's format for saving.
I need to code this in such a way that non-ColdFusion programmers can easily read this and use it, copy and modify it for other functions (such as adding a day to a date). So, I am not looking for the most least amount of code, but efficient and readable code.
Can you suggest anything that would make this code block more flexible, readable, or more efficient (less code)?
<cfscript>
// FORMAT DB DATE FOR BROWSER
DateFromDB = "20111116";
DatedToBrowser = createBrowserDate(DateFromDB);
writeOutput(DatedToBrowser);
function createBrowserDate(ThisDate) {
ThisYear = left(ThisDate, 4);
ThisMonth = mid(ThisDate, 4, 2);
ThisDay = right(ThisDate, 2);
NewDate = createDate(ThisYear, ThisMonth, ThisDay);
NewDate = dateFormat(NewDate, "MM/DD/YYYY");
return NewDate;
}
// FORMAT BROWSER DATE FOR DB
DateFromBrowser = "11/16/2011";
DateToDB = createDBDate(DateFromBrowser);
writeDump(DateToDB);
function createDBDate(ThisDate) {
ThisYear = year(ThisDate);
ThisMonth = month(ThisDate);
ThisDay = day(ThisDate);
NewDate = "#ThisYear##ThisMonth##ThisDay#";
return NewDate;
}
</cfscript>
First find who ever did the database and kick them in the nads...
Personally I'd Convert with sql so my code only dealt with date objects.
Select Convert(DateTime, Convert(VarChar(8),DateTimeInventedByIdjitColumn))
From SomeTable
As stated by our peers, store dates as dates.
'08/06/2011' could be 8th of june of the 6th of August depending on locale.
20111643 is a valid integer..
Not using a proper date type is just a massive collection of features and bugs that at best are waiting to happen.
You can actually rewrite each function into 1 line of code.
function createBrowserDate(ThisDate) {
return mid(ThisDate,4,2) & "/" & right(ThisDate,2) & "/" & left(ThisDate,4);
}
and
function createDBDate(ThisDate) {
return dateFormat( ThisDate, "YYYYMMDD" );
}
Don't keep dates as strings - keep dates as dates and format them when you need to.
If you can't correct the database to use actual date columns (which you should if you can), then you can use these two functions to convert to/from YYYYMMDD and a date object:
function parseYMD( YYYYMMDD )
{
if ( ! refind('^\d{8}$' , Arguments.YYYYMMDD ) )
throw "Invalid Format. Expected YYYYMMDD";
return parseDateTime
( Arguments.YYYYMMDD.replaceAll('(?<=^\d{4})|(?=\d{2}$)','-') );
}
function formatYMD( DateObj )
{
return DateFormat( DateObj , 'yyyymmdd' );
}
By using date objects it means that any level of developer can work with them, without needing to care about formatting, via built-in functions like DateAdd, DateCompare, and so on.
I'm not a regular expression fan since it's not that readable to me.
Since you're using CF9, I'd typed the argument and specify the returntype of the functions to be even more readable for the next person picking up your code.
First, right after I read the date from DB, I'd parse it to a Date object using parseDBDate()
Date function parseDBDate(required String dbDate)
{
var yyyy = left(dbDate, 4);
var mm = mid(dbDate, 4, 2);
var dd = right(dbDate, 2);
return createDate(yyyy , mm, dd);
}
Once you have the date object, you can use all those built-in Date functoin like DateAdd() or DateDiff().
Call browserDateFormat() right before you need to display it.
String function browserDateFormat(required Date date)
{
return dateFormat(date, "MM/DD/YYYY");
}
Call dBDateFormat() inside <cfqueryparam value=""> when it's time to persist to DB
String function dBDateFormat(required Date date)
{
return dateFormat(date, "YYYYMMDD");
}
One liner :)
myDateString = "20110203";
myCfDate = createObject("java","java.text.SimpleDateFormat").init("yyyyMMdd").parse(myDateString,createObject("java","java.text.ParsePosition").init(0*0));
If you want to parse different patterns, change "yyyyMMdd" to any other supported pattern.
http://download.oracle.com/javase/1.5.0/docs/api/java/text/SimpleDateFormat.html
The ParsePosition is used to say where to start parsing the string.
0*0 is shorthand for JavaCast("int",0) - in the Adobe cf engine, 0 is a string, until you apply math to it, then it becomes a Double, which the ParsePosition constructor supports. Technically, it constructs with an int, but cf is smart enough to downgrade a Double to an int.
http://download.oracle.com/javase/1.5.0/docs/api/java/text/ParsePosition.html