Return the time properly formatted - c#

I have this code that when the button is clicked it returns the current time. However it returns the time in a format that's pretty unreadable. How do I format this to look better?
using System;
using Microsoft.AspNetCore.Mvc;
using Clockwork.API.Models;
namespace Clockwork.API.Controllers
{
[Route("api/[controller]")]
public class CurrentTimeController : Controller
{
// GET api/currenttime
[HttpGet]
public IActionResult Get()
{
var utcTime = DateTime.UtcNow;
var serverTime = DateTime.Now;
var ip = this.HttpContext.Connection.RemoteIpAddress.ToString();
var returnVal = new CurrentTimeQuery
{
UTCTime = utcTime,
ClientIp = ip,
Time = serverTime
};
using (var db = new ClockworkContext())
{
db.CurrentTimeQueries.Add(returnVal);
var count = db.SaveChanges();
Console.WriteLine("{0} records saved to database", count);
Console.WriteLine();
foreach (var CurrentTimeQuery in db.CurrentTimeQueries)
{
Console.WriteLine(" - {0}", CurrentTimeQuery.UTCTime);
}
}
return Ok(returnVal);
}
}
}
It returns like this :
{"currentTimeQueryId":15,"time":"2018-08-19T11:44:54.3348267-04:00","clientIp":"127.0.0.1","utcTime":"2018-08-19T15:44:54.3348267Z"}

You shouldn't try to change it at all.
That's an ISO-8601-formatted date and time including a UTC offset. That's good - it's easy to parse for pretty much any system out there. It's unambiguous, and doesn't have any culture-specific details like day and month names. It's great - for machines to read.
You're producing JSON, which is intended to be machine-readable, not human-readable. Sure, as an interchange format it is pretty readable, but it's not intended to be displayed to an end user. Instead, whatever is presenting the data to the end user should perform whatever formatting is appropriate for the date/time value. It's really important not to try to do that in the data transport format intended for machines (JSON in this case) as it can often lead to ambiguity or pointless culture-sensitivity.
Note that this isn't just for dates and times. Take a numeric value, for example: while 10.5 may be "human-readable" to you, it's not how someone in France would want to see "10 and a half". They'd format that as "10,5". But I wouldn't recommend using that string in the JSON: I'd make it 10.5 (as a number, not a string1) and then perform the "number to human-readable-format" conversion in Javascript.
Basically, keep data as presentation-agnostic as possible all the way through your data pipeline until it reaches the presentation layer, which should have all the cultural information required to format it ideally for the actual user. Very often you don't have all that cultural information elsewhere in the pipeline.
1 Unless you're trying to account for JSON being binary floating point when you're trying to represent a strictly decimal number. It's unfortunate that there's no real decimal format in JSON.

You can try
DateTime.Now.ToShortTimeString();

Related

c# DateTime.Parse precision Issue

Quick question about precision with DateTime.Parse in c#?
I have multiple input files that I am consolidating into one list of lines, which I will then order by DateTime.
This is fine, except the Parse function seems to handle the date incorrectly when the milliseconds is only 2 digits, in the case below it treats 09:57:44.84 as 09:57:44.840 instead of 09:57:44.084
List<DateTime> lstUnOrdered = new List<DateTime>();
lstUnOrdered.Add(DateTime.Parse("04/09/2020 09:57:44.573", CultureInfo.InvariantCulture));
lstUnOrdered.Add(DateTime.Parse("04/09/2020 09:57:44.84", CultureInfo.InvariantCulture));
var Ordered = lstUnOrdered.OrderBy(x => x.TimeOfDay);
foreach (var item in Ordered)
{
Console.WriteLine(item.ToString("dd/MM/yyyy HH:mm:ss.fff"));
}
When run, you get the following Output
09/04/2020 09:57:44.573
09/04/2020 09:57:44.840
I Expected this Output
09/04/2020 09:57:44.084
09/04/2020 09:57:44.573
Any suggestions on where I may be going wrong?
Thanks
EDIT:
Based on the comments below, just a few updates:
"Fundamentally: whatever is generating these values is broken, and should be fixed. If that's impossible for you, you should patch the data before parsing it, by inserting extra 0s where necessary. "
-- This is correct, I have no control over the data. But I do know that the order in the input file is :
09/04/2020 09:57:44.84
09/04/2020 09:57:44.573
This tells me the date should be 084 and not 840, I'm not disputing Parse is incorrect, just looking for alternatives to parse these dates with more precision, rather then having to write another method to sanitize the date string first.
I can of course split the string on the . and add 1 or 2 zeroes if needed, was hoping .Net had an inbuilt way for doing this with DateTime.Parse or alternative.
Thanks
Just an Update, This will fix the issue with the bad input string in case anyone is wondering:
static void Main(string[] args)
{
List<DateTime> lstUnOrdered = new List<DateTime>();
lstUnOrdered.Add(DateTime.Parse(MakeCorrectDate("04/09/2020 09:57:44.573"),
CultureInfo.InvariantCulture));
lstUnOrdered.Add(DateTime.Parse(MakeCorrectDate("04/09/2020 09:57:44.84"), CultureInfo.InvariantCulture));
var Ordered = lstUnOrdered.OrderBy(x => x.TimeOfDay);
foreach (var item in Ordered)
{
Console.WriteLine(item.ToString("dd/MM/yyyy HH:mm:ss.fff"));
}
}
private static string MakeCorrectDate(string strDate)
{
string[] milli = strDate.Split('.');
return milli[0] + "." + milli[1].PadLeft(3, '0');
}

C# - How do I get a user input for date and time

I want to be able to get a point from a database using the date and time the point was created. I want to do this by asking the user what date/time they want and then use that date/time to find the point. This is my code currently, it gets the point but only the data from the exact time I run the code. I would like to be able to get data from a 6/4/2012 4:50:29 for example.
//connect to pi server
PIServers piServers = new PIServers();
foreach (var server in piServers)
{
Console.WriteLine("Server: {0}", server.Name);
}
PIServer piServer = piServers.DefaultPIServer;
Console.WriteLine("Default Server: {0}", piServer.Name);
piServer.Connect();
//get a PI Point
var point = PIPoint.FindPIPoint(piServer, "Pipoint");
var value = point.Snapshot();
Console.WriteLine("Point {0} Value {1} {2}", point.Name,
value.Value.ToString(),value.Timestamp.ToString());
Thank you very much for the help.
What you need to do is first ask the user:
Console.WriteLine("Enter date");
var userInput = Console.ReadLine();
Now userInput is a string so you need to cast it into a DateTime object, I would not cast it directly since it is very easy to get a InvalidCastException, so we should use the built in TryParse(String, out DateTime) to validate if it is a correct DateTime.
DateTime result;
DateTime.TryParse(userInput, out result);
If userInput was a correct DateTime then the result will be a valid DateTime object. If it was not correct the result will be DateTime.MinValue so I would check:
if(!result.Equals(DateTime.MinValue))
{
// Continue to look it up in the DB
}
You have to get an input from a user and store that value in a variable.
I am assuming var point = PIPoint.FindPIPoint(piServer, "Pipoint"); is the line of code that queries the DB for a match.
In that case you would want to pass the datetime as a string. string input = Console.Readline(); and then just pass userInput to the FindPIPoint method.
But if the .FindPiPoint method is looking for a datetime you would need to cast it to a datetime object first.
Since this is working on the assumption that any possible datetime is a possible match(and I doubt this is the case) you should add some error handling for an incorrect match.

Convert DateTime to string using another string as a template

I have a string that contains a date & time in some format. For example:
13:53:56 20.08.2014
This string is parsed from a file that user uploads to my service. The exact date & time format is not known. It can change to pretty much any date & time format you know. I do not have a list a expected formats or anything like that.
I want to develop an algorithm that somehow extracts the format from the initial string and applies it to, say, DateTime.Now.
Is there any way to do this simply and elegantly?
If you know the list of expected formats, then define them and use DateTime.TryParseExact() to find out the matching format of your input string. Once you have the matching format, you can simply use the matching format with DateTime.Now.ToString(format).
If this is a web application, perhaps you can "cheat a bit" by sniffing the user's regional settings before they input the string.
The MSDN article "How to: Display Localized Date and Time Information to Web Users" has useful information.
Inspired by a good suggestion by Mani, I've created the following extension method for my needs:
public static bool TryFormatLike(this DateTime dateTime, string another, out string result)
{
var allCultures = CultureInfo.GetCultures(CultureTypes.AllCultures | CultureTypes.UserCustomCulture | CultureTypes.ReplacementCultures);
foreach (var culture in allCultures)
{
var allPatterns = culture.DateTimeFormat.GetAllDateTimePatterns();
foreach (var pattern in allPatterns)
{
DateTime parsedAnother;
if (DateTime.TryParseExact(another, pattern, culture.DateTimeFormat, DateTimeStyles.AllowWhiteSpaces, out parsedAnother))
{
result = dateTime.ToString(pattern);
return true;
}
}
}
result = string.Empty;
return false;
}
You can use it like that:
string formattedNow;
if (DateTime.Now.TryFormatLike("13.02.2015 16:14:43", out formattedNow))
{
Console.WriteLine(formattedNow);
}
This will print
10.03.2015 23:37:08
Unfortunately, some date & time formats cannot be parsed by all patters in all cultures (for instance, string 16:14:43 13.02.2015 will not be parsed).
Anyway, thank you for your comments & answers. Maybe this method will be helpful to someone.

On searching documents in mongodb collection using ISODate range, I get the error "String was not recognized as a valid DateTime"

I am trying to query MongoDB using the following -
List<BsonDocument> list = NoSqlBusinessEntityBase.LoadByWhereClause("peoplecounting",
string.Concat("{siteid:\"", siteid, "\", locationid:\"", location._id ,"\",
StartTime: {$gte:ISODate(\"",old.ToString("yyyy-mm-dd hh:mm:ss"),"\")},
EndTime: {$lte:ISODate(\"",current.ToString("yyyy-MM-dd hh:mm:ss"), "\"\")}}"));
The LoadByWhereClause() function is as follows -
public static List<BsonDocument> LoadDataByWhere(string table, string whereClause)
{
var collection = db.GetCollection(table);
QueryDocument whereDoc = new QueryDocument(BsonDocument.Parse(whereClause));
var resultSet = collection.Find(whereDoc);
List<BsonDocument> docs = resultSet.ToList();
if (resultSet.Count() > 0)
{
foreach (BsonDocument doc in docs)
{
doc.Set("_id", doc.GetElement("_id").ToString().Split('=')[1]);
}
return docs;
}
else
{
return null;
}
}
Even though the query runs fine in MongoDB console and returns documents
db.peoplecounting.find({siteid:"53f62abf66455068373665ff", locationid:"53f62bb86645506837366603",
StartTime:{$gte:ISODate("2012-12-03 02:40:00")}, EndTime:{$lte:ISODate("2013-12-03 07:40:00")}}
I get the error when I try to load in C# using the LoadByWhereClause function. The error is String was not recognized as a valid DateTime. while parsing the whereClause.
How can I possibly fix this? I am unable to determine what is going wrong here.
It's not entirely clear, but I suspect the problem may well be how you're formatting the date. This:
old.ToString("yyyy-mm-dd hh:mm:ss")
should almost certainly be this:
old.ToString("yyyy-MM-dd HH:mm:ss")
or possibly
old.ToString("yyyy-MM-dd'T'HH:mm:ss")
Because:
mm means minutes. You don't want the minutes value between your year and day-of-month; you want the month (MM)
hh means "hour of half-day" (i.e. 1-12). You want the hour of full day, 0-23 (HH)
ISO-8601 uses a T literal to separate the date frmo the time.
I note that your current.ToString is better, but not correct - it gets the month right, but not the hour. The fact that these are inconsistent is a problem to start with - I would advise you to write a separate method to convert a DateTime appropriately.

Parse date of ISO 8601 value 24:00:00 fails

I'm trying to parse incoming date from data source (which cannot be changed). It gives me time in ISO 8601 format example: 2007-04-05T24:00.
How ever in .Net it fails to parse this as valid time.
The wikipedia states that it should be valid format. Wikipedia ISO 8601
Example from https://stackoverflow.com/a/3556188/645410
How can I do this without a nasty string check hack?
Example (fiddle: http://dotnetfiddle.net/oB7EZx):
var strDate = "2007-04-05T24:00";
Console.WriteLine(DateTime.Parse(strDate, null, DateTimeStyles.RoundtripKind));
Throws:
The DateTime represented by the string is not supported in calendar
System.Globalization.GregorianCalendar.
Yes, .NET doesn't support this as far as I'm aware.
My Noda Time project does, but only partially: it can parse the value, but the value is just parsed to midnight at the start of the next day, and is never formatted as 24:00. There's nothing in the Noda Time conceptual model to represent "the end of the day".
Sample code to show what's possible:
using System;
using NodaTime;
using NodaTime.Text;
class Test
{
static void Main()
{
string text = "2007-04-05T24:00";
var pattern = LocalDateTimePattern.CreateWithInvariantCulture
("yyyy-MM-dd'T'HH:mm");
var dateTime = pattern.Parse(text).Value;
Console.WriteLine(pattern.Format(dateTime)); // 2007-04-06T00:00
}
}
If you don't mind losing the difference between inputs of "2007-04-05T24:00" and "2007-04-05T00:00" then you're probably okay.
Here is one simple solution — it updates this kind of end-of-the-day values to the start-of-the-next-day:
using System;
using System.Text.RegularExpressions;
namespace Iso8601ToDateTime
{
class Program
{
string text = "2021-12-31T24:00:00+01:00";
var pattern = #"^([-\d]+)(T24)";
var replaced = Regex.Replace(text, pattern,
m => DateTime.Parse(m.Groups[1].Value)
.AddDays(1).ToString("yyyy-MM-dd") + "T00");
Console.WriteLine(replaced); // 2022-01-01T00:00:00+01:00
}
}
UPDATED: Fixed bug based on raznagul's comment.

Categories

Resources