NancyFX not serializing dates with a trailing Z to indicate UTC/Zulu - angularjs

We store all of our dates in our database as UTC.
When they are returned to us from the API, they are in the following format
"createdDate":"2014-07-30T18:34:45"
But as you can see, the date doesn't have the trailing Z (which indicates to our Angular app that it's UTC / Zulu). It should look like this
"createdDate":"2014-07-30T18:34:45Z"
I do have the following setting in our Bootstrapper
JsonSettings.ISO8601DateFormat = true;
Where in my config can I ensure that there's a trailing Z for the purpose of UTC parsing?

What version of NancyFx are you using? Because in v0.23.0 or later, the JsonSerializer code has been changed to use the "o" date format instead of the "s" date format, which should give you the trailing Z that you're looking for. (But only on UTC datetimes.)
This is the commit that made this change. Note how DateTimeKind.Unspecified dates are treated as local; that might be one possible cause of your problem, if you're not explicitly creating your DateTime objects as DateTimeKind.Utc.
Below is the NancyFx code that serializes DateTime values, as it looks as of v0.23.0 (after that commit). From https://github.com/NancyFx/Nancy/blob/v0.23.0/src/Nancy/Json/JsonSerializer.cs, lines 480-518:
void WriteValue (StringBuilder output, DateTime value)
{
if (this.iso8601DateFormat)
{
if (value.Kind == DateTimeKind.Unspecified)
{
// To avoid confusion, treat "Unspecified" datetimes as Local -- just like the WCF datetime format does as well.
value = new DateTime(value.Ticks, DateTimeKind.Local);
}
StringBuilderExtensions.AppendCount(output, maxJsonLength, string.Concat("\"", value.ToString("o", CultureInfo.InvariantCulture), "\""));
}
else
{
DateTime time = value.ToUniversalTime();
string suffix = "";
if (value.Kind != DateTimeKind.Utc)
{
TimeSpan localTZOffset;
if (value >= time)
{
localTZOffset = value - time;
suffix = "+";
}
else
{
localTZOffset = time - value;
suffix = "-";
}
suffix += localTZOffset.ToString("hhmm");
}
if (time < MinimumJavaScriptDate)
time = MinimumJavaScriptDate;
long ticks = (time.Ticks - InitialJavaScriptDateTicks)/(long)10000;
StringBuilderExtensions.AppendCount(output, maxJsonLength, "\"\\/Date(" + ticks + suffix + ")\\/\"");
}
}
As you can see, requesting ISO 8601 date format will get you the 2014-07-30T18:34:45 format rather than the number of milliseconds since the epoch, but it will assume local times if the value being serialized has a Kind equal to DateTimeKind.Local.
So I have two suggestions for you: upgrade to v0.23 of NancyFx if you're still on v0.22 or earlier (v0.22 used the "s" date format, which does not include timezone info, for serializing DateTime values). And if the DateTime objects you're serializing aren't explicitly set to DateTimeKind.Utc, then make sure you specify Utc (since the default is Unspecified, which NancyFx treats as equivalent to Local).

Related

Date/Time Formatting in React

I am working with an API that returns Dates in the format 2022-03-01T11:32:37
Created: {this.props.proposal.OPENWHEN}
Created: 2022-03-01T11:32:37
How do i format this into DD/MM/YYY 24:00:00 ?
Thanks In Advance
Something like the following should be enough:
// Example expected argument: 2022-03-01T11:32:37
function prettifyDateTime (str) {
// Splitting the string between date and time
const [date, time] = str.split("T");
// Assuming 03 is the month and 01 is the day – otherwise, those could be swapped
const [year, month, day] = date.split("-")
// Added slashes and the space before the time
return `${day}/${month}/${year} ${time}`
}
prettifyDateTime("2022-03-01T11:32:37") // '01/03/2022 11:32:37'
Otherwise, I recommend using a date library like date-fns, dayJS, or moment.
You can use the Date object to accomplish what you want. It'll also accept other date formats. Here is one place to find Date description. You also get the benefit of rejecting invalid date formats
function prettifyDateTime(str) {
let date = new Date(str);
// There's other ways of formatting this return
return date.toLocaleDateString() + ' ' + date.toLocaleTimeString();
}

EF Core query only DateTime of DateTimeOffset cannot be translated;

I'm having an issue where I want to query based on the DateTime only of a DateTimeOffset SQL Server column and I'm wondering if it's possible to do with EF Core.
If I have appointments all over the world and my business logic is recording them in their local DateTimeOffset accurately, I want to be able to get the appointments of a specific day regardless of time zone, however, I get an exception that the query cannot be translated when I try the following:
public class Appointment
{
public int Id {get;set;}
public DateTimeOffset BeginTime {get;set;}
}
DateTime queryDay = new DateTime(2021, 1, 1);
var results = dbContext.Appointments.Where(a => a.BeginTime.DateTime >= queryDate && a.BeginTime.DateTime < queryDay.AddDays(1)).ToList();
Is there anyway to do this with EF Core? I mean, in the example, I'm just trying to get a specific date, but, in reality, I want to be able to do it for any datetime with any time values, etc.
In other words, I'm not looking to filter by a universal time range, but, rather, by a time ranges without the offset considered.
Doesn't seem to work even if I create a [NotMapped] property that returns BeginTime.DateTime.
Edit:
Exact error:
System.InvalidOperationException: The LINQ expression 'DbSet()
.Where(t => True && t.BeginTime.DateTime >= __fakeStartDate_1 && t.BeginTime.DateTime < __fakeEndDate_2)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
SqlServer provider supports the so called "double cast" construct (first to object, then to other type, e.g. (DateTime)(object)) which tricks the C# compiler to accept a conversion which normally fails (and will fail if executed in LINQ to Objects context), and EF Core translator, forcing the latter to emit conversion from datetimeoffset to datetime2 using CASToperator.
e.g.
var query = dbContext.Appointments
.Where(a => ((DateTime)(object)a.BeginTime) >= queryDate
&& ((DateTime)(object)a.BeginTime) < queryDate.AddDays(1));
succesfully translates to
DECLARE #__queryDate_0 datetime2 = '2021-01-01T00:00:00.0000000';
DECLARE #__AddDays_1 datetime2 = '2021-01-02T00:00:00.0000000';
SELECT [a].[Id], [a].[BeginTime]
FROM [Appointments] AS [a]
WHERE (CAST([a].[BeginTime] AS datetime2) >= #__queryDate_0) AND (CAST([a].[BeginTime] AS datetime2) < #__AddDays_1)
There is a round about way that I don't like so much but it doesn't avoid the index on the column and it should work. It would be something like this:
public IEnumerable<Appointments> GetAppointments(DateTime start, DateTime end)
{
var bufferStart = start.AddDays(-1);
var bufferEnd = end.AddDays(1);
return dbContext.Appointments
.Where(a => a.BeginTime >= bufferStart && a.BeginTime < bufferEnd)
.AsEnumerable()
.Where(a => a.BeginTime.DateTime >= start && a.BeginTime.DateTime < end);
}
Obviously, there's a bunch of reasons I don't like this so still looking for a better answer. Would be grateful if anyone has one.

How to check if a string date has passed a certain date

I have these strings:
yy = "19";
mm = "05";
dd = "31";
These represent the creation date of a certain object in my project. This object expires after one month. How do I check if the object has expired already?
(I came across this solution but thought there might be another way to do it.)
UPDATE: the string date apparently represent the actual expiry date
I ended up using the date format "yymmdd" so I can convert it to type long and do a simple number comparison.
sprintf(buffer, "%s%s%s", yy, mm, dd);
expiryDate = atol(buffer);
// get current date of format "yymmdd" as well
// getCurrentDate() is my function that gets the date from my SDK
currentDate = getCurrentDate();
if(expiryDate >= currentDate)
{
// expired object!
}

Epoch 0 to Date conversion using momnet.js

I need to convert my epoch date to a Date object. I did this using the following code.
let abc = moment(maintenance.actualEndDate * 1000).format('DD/MMM/YYYY hh:mm');
but there is a high chance to 0 as the value for 'maintenance.actualEndDate'.
in this case the transalated date is showing the value as '01/01/1970 12:00'.
I actually need as an empty string in variable abc if the maintenance.actualEndDate is 0
I'm working on angular 4, is there any optimal solution to this?
If what you need is converting non-zero timestamps to a formatted date, and zero timestamps as empty string, a dedicated function would be nice:
function formatTimestamp(secondsSinceEpoch) {
return secondsSinceEpoch===0 ? '' : moment.unix(secondsSinceEpoch).format('DD/MMM/YYYY HH:mm');
}
//...
let abc = formatTimestamp(maintenance.actualEndDate);
(But this has nothing specific to angular)

SQlite creating a database with a timestamp column and adding a value in

I am trying to create a database that called rawData. The db will hava a column for the id, a foreign user id (_id from another table), data and finally a timestamp.
My question is how can I create a timestamp in SQlite and store it in the db also what type should the column be, text? the database needs to be able to store 150 float values a second and time stamp each of those 150 entries. Additionally since SQlite doesn't have a float type should i use real as the column type?
public class RawDatabase{
public static final String TABLE_RAW_DATA = "rawData";
public static final String COLUMN_ID = "_id";
public static final String COLUMN_FOREIGN_USER_ID = "foreignUserId";
public static final String COLUMN_DATA = "data";
public static final String COLUMN_TIME_STAMP = "timeStamp";
// Database creation sql statement
private static final String DATABASE_CREATE = "create table "
+ TABLE_RAW_DATA + "(" + COLUMN_ID
+ " integer primary key autoincrement, " + COLUMN_FOREIGN_USER_ID
+ " integer, " + COLUMN_DATA
+ " real, " + COLUMN_TIME_STAMP
+ " text not null);";
}
The documentation says:
SQLite does not have a storage class set aside for storing dates and/or times. Instead, the built-in Date And Time Functions of SQLite are capable of storing dates and times as TEXT, REAL, or INTEGER values:
TEXT as ISO8601 strings ("YYYY-MM-DD HH:MM:SS.SSS").
REAL as Julian day numbers, the number of days since noon in Greenwich on November 24, 4714 B.C. according to the proleptic Gregorian calendar.
INTEGER as Unix Time, the number of seconds since 1970-01-01 00:00:00 UTC.
Applications can chose to store dates and times in any of these formats and freely convert between formats using the built-in date and time functions.
If you need only seconds precision, use integers in Unix Time format.
Otherwise, use floating-pointer numbers for fractional seconds.
This is a running example of DAO with SQlite and Date in Java:
First create column MY_DATE TIMESTAMP in your TABLE and populate like this:
PreparedStatement st = connection.prepareStatement("INSERT INTO ......");
st.setDate(1, new java.sql.Date(lettura.getData().getTime()));
And to retrieve data first i get date in String type:
String dateStr = rs.getString(1);
Date myDate = new java.util.Date(Long.parseLong(dateStr));

Resources