I have created an API end-point. The caller may call the API with POST method passing the relevant parameters. In the parameters there is one parameter that is of datetime format.
The problem is that when calling this API the caller may passes datetime in 3 different formats:
long int - e.g. 1374755180
US format - e.g. "7/25/2013 6:37:31 PM" (as string)
Timestamp format - e.g. "2013-07-25 14:26:00" (as string)
I have to parse the datetime value and convert it to a DateTime or string in Timestamp format.
I have tried using DateTime.TryParse(), DateTime.Parse(), Convert.ToDateTime() and Convert.ToDouble() but none of them are working in certainty for me.
The required output has to be in en-GB format.
Edit:
I had thought to have an if-else if-else block to use with TryParse 3 times with one else to say the string could not be parsed. Is this the best solution? Or are there solutions better than this?
Please help!
You should consider requiring a timezone.
1 doesn't need it, but #2 and #3 do.
public DateTime ParseRequestDate()
{
// https://stackoverflow.com/questions/2883576/how-do-you-convert-epoch-time-in-c
CultureInfo enUS = new CultureInfo("en-US");
var dt = "1374755180";
//var dt = "7/25/2013 6:37:31 PM";
//var dt = "2013-07-25 14:26:00";
DateTime dateValue;
long dtLong;
// Scenario #1
if (long.TryParse(dt, out dtLong))
return dtLong.FromUnixTime();
// Scenario #2
if (DateTime.TryParseExact(dt, "MM/dd/yyyy hh:mm:ss tt", enUS, DateTimeStyles.None, out dateValue))
return dateValue;
// Scenario #3
if (DateTime.TryParseExact(dt, "yyyy-MM-dd hh:mm:ss", enUS, DateTimeStyles.None, out dateValue))
return dateValue;
throw new SomeException("Don't know how to parse...");
}
EDIT
As Matt Johnson points out, DateTime.TryParseExact accepts an array of format strings.
2 & 3 could be condensed.
public DateTime ParseRequestDate()
{
// https://stackoverflow.com/questions/2883576/how-do-you-convert-epoch-time-in-c
CultureInfo enUS = new CultureInfo("en-US");
var dt = "1374755180";
//var dt = "7/25/2013 6:37:31 PM";
//var dt = "2013-07-25 14:26:00";
DateTime dateValue;
long dtLong;
// Scenario #1
if (long.TryParse(dt, out dtLong))
return dtLong.FromUnixTime();
// Scenario #2 & #3
var formatStrings = new string[] { "MM/dd/yyyy hh:mm:ss tt", "yyyy-MM-dd hh:mm:ss" };
if (DateTime.TryParseExact(dt, formatStrings, enUS, DateTimeStyles.None, out dateValue))
return dateValue;
throw new SomeException("Don't know how to parse...");
}
The epoch conversion I borrowed from another question.
(An extension method)
public static class MyExtensions
{
public static DateTime FromUnixTime(this long unixTime)
{
var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
return epoch.AddSeconds(unixTime);
}
}
You are looking for the DateTime.ParseExact (MSDN Article)
Which you would use in a situation like this:
string[] formats= { "MM/dd/yyyy hh:mm:ss tt", "yyyy-MM-dd hh:mm:ss" }
var dateTime = DateTime.ParseExact("07/25/2013 6:37:31 PM", formats, new CultureInfo("en-GB"), DateTimeStyles.None);
This allows you to add as many DateTime formats to the array as you need and the method will do the conversion without the if...else statements.
If your integer is in seconds since Unix Epoch you add the number of seconds to the DateTime of the Epoch (01/01/1970) (.Net doesn't have an out of the box method for this, but the logic is seconds since 'Epoch'):
new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(seconds);
From this question.
I was facing same problem in a project where my code will run on different environments with various culture formats.
Google showed me this hidden gem. The helper function is indispensable to auto-parse datetime properly regardless of culture formats
Usage Examples:
string str = #"The last round was June 10, 2005; this time the unbroken record was held.";
DateTimeRoutines.ParsedDateTime pdt;
if (DateTimeRoutines.TryParseDate(str, DateTimeRoutines.DateTimeFormat.USA_DATE, out pdt))
Console.WriteLine("Date was found: " + pdt.DateTime.ToString());
According to the author, the code is capable of parsing various cases:
#"Member since: 10-Feb-2008"
#"Last Update: 18:16 11 Feb '08 "
#"date Tue, Feb 10, 2008 at 11:06 AM"
#"see at 12/31/2007 14:16:32"
#"sack finish 14:16:32 November 15 2008, 1-144 app"
#"Genesis Message - Wed 04 Feb 08 - 19:40"
#"The day 07/31/07 14:16:32 is "
#"Shipping is on us until December 24, 2008 within the U.S."
#" 2008 within the U.S. at 14:16:32"
#"5th November, 1994, 8:15:30 pm"
#"7 boxes January 31 , 14:16:32."
#"the blue sky of Sept 30th 2008 14:16:32"
#" e.g. 1997-07-16T19:20:30+01:00"
#"Apr 1st, 2008 14:16:32 tufa 6767"
#"wait for 07/31/07 14:16:32"
#"later 12.31.08 and before 1.01.09"
#"Expires: Sept 30th 2008 14:16:32"
#"Offer expires Apr 1st, 2007, 14:16:32"
#"Expires 14:16:32 January 31."
#"Expires 14:16:32 January 31-st."
#"Expires 23rd January 2010."
#"Expires January 22nd, 2010."
#"Expires DEC 22, 2010."
One way to deal with this problem would be setting up a factory method that "understands" different formats, and parses them accordingly.
You can create a chain of if-then-elses to deal with this problem, but you can also make a "table-driven" implementation: what you need is an array of delegates that take a string, and tell you two things:
Whether or not this delegate can parse the incoming string, and
If yes, what is the result of that parse, expressed as DateTime
Here is a sample implementation:
private static readonly DateParsers = new Func<string,Tuple<DateTime,bool>>[] {
(s) => {
long res;
if (long.TryParse(s, out res)) {
// The format was correct - make a DateTime,
// and return true to indicate a successful parse
return Tuple.Create(new DateTime(res), true);
} else {
// It does not matter what you put in the Item1
// when Item2 of the tuple is set to false
return Tuple.Create(DateTime.MinValue, false);
}
}
...
// Add similar delegates for other formats here
};
Now your factory method could be implemented as follows:
private static bool TryParseMultiformat(string s, out DateTime res) {
// Check all parsers in turn, looking for one returning success
foreach (var p in DateParsers) {
var tmp = p(s);
if (tmp.Item2) {
res = tmp.Item1;
return true;
}
}
res = DateTime.MinValue;
return false;
}
If the possible formats are fixed then you can use TryParseExact
A possible solution is to use TryParse, if it fails to get proper date then fallback to known formats and use TryPraseExact
Thanks for your answers. I tried the options suggested in couple of answers and found out a very simple approach that worked for me.
public static bool ParseDate(string dateString, out DateTime dateValue)
{
long dtLong = 0L;
bool result = false;
if (long.TryParse(dateString, out dtLong))
{
// I copied the epoch code here for simplicity
dateValue = new DateTime(1970, 1, 1, 0, 0, 0).AddSeconds(dtLong);
result = true;
}
// Working for US and Timestamp formats
else if (DateTime.TryParse(dateString, out dateValue))
result = true;
return result;
}
Earlier I was trying to use TryParse for all the 3 formats which was not working.
Somehow, TryParseExact did not work for the timestamp format. It worked for the US format. That is the reason I had to write my own.
If you use TryParseExact, only G-O-D and the Microsoft developers know how many possible date time formats it will try to parse before it gives up. Perhaps a better solution is to use a quick regex and then an appropriate parser. I tried to make the regex as simple as possibke, you may have to tweak this a little
private static readonly Regex R1
= new Regex(#"^\d+$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
private static readonly Regex R2
= new Regex(#"M$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
private static readonly Regex R3
= new Regex(#"^\d{4}-", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
private static void Main(string[] args)
{
string[] stringDates = new[]
{
"1374755180",
"2013-07-25 14:26:00",
"7/25/2013 6:37:31 PM"
};
foreach (var s in stringDates)
{
DateTime date = default(DateTime);
if (R1.IsMatch(s))
date = new DateTime(long.Parse(s));
else if (R2.IsMatch(s))
date = DateTime.Parse(s);
else if (R3.IsMatch(s))
date = DateTime.Parse(s);
if (date != default(DateTime))
Console.WriteLine("{0}", date);
}
Console.WriteLine("Press ENTER to continue...");
Console.ReadLine();
}
Related
I am trying a more efficient way to write this datetime function shown here, so that it can still give a correct date whether the datetime is in 24 hour notation or not. Currently, it works but throws errors when the notation changes.
using System;
using System.Web;
using System.Globalization;
class Program
{
private static string req = "01/26/2023 5:32 PM";
private static int hourNotation;
private static DateTime? expectedDate;
static void Main(string[] args)
{
Console.WriteLine("Hello, world!");
hourNotation = Convert.ToInt32(req[11].ToString());
// Task task = Task.Delay(1000);
if (hourNotation >= 1)
{
expectedDate = DateTime.ParseExact(req.Substring(0, req.Length - 3), "MM/dd/yyyy HH:mm",
new CultureInfo("en-US"),
DateTimeStyles.None);
Console.WriteLine("greater than 10");
}
else
{
expectedDate = DateTime.ParseExact(req.Substring(0, req.Length - 3), "MM/dd/yyyy h:mm",
new CultureInfo("en-US"),
DateTimeStyles.None);
Console.WriteLine("Less than 10");
}
}
}
You can greatly simplify this by using one the ParseExact() overloads that accepts an array of formats.
Just keep in mind: they mean it when they use "Exact" in the ParseExact() name. If your formats are not defined perfectly you'll get exceptions at run time. In this case, the format string for the 12 hour format is not right, because it's missing the time of day specifier. So you need this:
MM/dd/yyyy h:mm tt
Additionally, if you're allowing users to enter date or time values by hand, you WILL eventually (usually sooner than later) have users enter ambiguous or unparseable data. In this case, we see it expects the U.S. format, so a common failure is a visitor from the UK will naturally cause something like 29/1/2023 to go in the field, because that's how they and everyone else from that country have always done it. Even worse, they'll use 3/2/2023 expecting to get Feb 3 instead of March 2.
Better to have UI support to help the user select a date or time value via a guided process or clock/calendar control of some kind, and immediately show unambiguous feedback (using the written month name) of how an input will be interpreted.
What about:
using System.Globalization;
class Program
{
private static string req = "01/26/2023 21:32";
private static List<string> dates = new List<string> { "01/26/2023 21:32", "01/26/2023 1:32", "01/26/2023 1:32 AM", "01/26/2023 11:32 PM" };
private static DateTime? expectedDate;
static void Main(string[] args)
{
Console.WriteLine("Hello, world!");
foreach (string date in dates)
{
var isTwelveHour = date.ToUpper().Contains("PM") | date.ToUpper().Contains("AM");
expectedDate = isTwelveHour
? DateTime.ParseExact(date, "MM/dd/yyyy h:mm tt",
new CultureInfo("en-US"),
DateTimeStyles.None)
: DateTime.ParseExact(date, "MM/dd/yyyy H:mm",
new CultureInfo("en-US"),
DateTimeStyles.None);
var clock = isTwelveHour ? "12 Hour Clock" : "24 Hour Clock";
Console.WriteLine($"{clock} : {expectedDate.ToString()}");
}
}
}
If I have a string like 15:00 and I parse this to DateTime ot DateTimeOffset, the date is set to today.
I want somehow to distinguish, if the date part is given or not. It would help, if the date part is not given, the date is 1.1.1970.
Is there a better possibility instead of using regex and parse this by my own?
Try to parse the value as TimeSpan and then try to parse it as DateTime.
var data = "15:00";
if (TimeSpan.TryParse(data, out var time))
{
Console.WriteLine("Time: {0}", time);
}
else if (DateTime.TryParse(data, out var datetime))
{
Console.WriteLine("DateTime: {0}", datetime);
}
else
{
Console.WriteLine("I don't know how to parse {0}", data);
}
If I have a string like "15:00" and I parse this to DateTime ot
DateTimeOffset, the date is set to today.
This is by design.
From DateTime.Parse doc:
A string with a time but no date component. The method assumes the
current date unless you call the Parse(String, IFormatProvider,
DateTimeStyles) overload and include
DateTimeStyles.NoCurrentDateDefault in the styles argument, in which
case the method assumes a date of January 1, 0001.
From DateTimeOffset.Parse doc:
If is missing, its default value is the current day.
So, for DateTime, if you don't use any DateTimeStyles, you get the current date
var hours = "15:00";
var date = DateTime.Parse(hours, CultureInfo.InvariantCulture); // 12/9/2018 3:00:00 PM
but if you use DateTimeStyles.NoCurrentDateDefault as a third parameter;
var hours = "15:00";
var date = DateTime.Parse(hours, CultureInfo.InvariantCulture, DateTimeStyles.NoCurrentDateDefault);
// 1/1/0001 3:00:00 PM
But I think your problem keeps on that sentence; "if the date part is given or not.." How did you decide your string has date part or not? Is it always have 5 characters as Steve commented? It can be in a format like 4:00? What about 4:1? If it can be like 4:1, it should be parsed as 4:10 or 4:01?
So, you need to decide first what is the meaning of "if the date part is given or not.." for your case. Then you can easily parse your string to TimeSpan, not DateTime in my opinion, so, you can add it created manually "1.1.1970" with DateTime(int, int, int) constructor.
if(YourConditionForYourStringNotIncludingDatePart)
{
var time = TimeSpan.Parse("15:00");
var date = new DateTime(1970, 1, 1);
var result = date.Add(time);
}
Using regular expressins for DateTime parsing is usually a bad idea. I wouldn't suggest to use it unless you have no other way to do it for DateTime.
I think for that case you could things keep simple. This could be a solution that not depends on the lenght when there is only a timepart:
void Main()
{
Console.WriteLine(ParseWithDummyIfDateAbsent("15:00", new DateTime(1970, 1, 1)));
Console.WriteLine(ParseWithDummyIfDateAbsent("15:00:22", new DateTime(1970, 1, 1)));
Console.WriteLine(ParseWithDummyIfDateAbsent("09.12.2018 15:00", new DateTime(1970, 1, 1)));
}
DateTime ParseWithDummyIfDateAbsent(string input, DateTime dummyDate)
{
if(TimeSpan.TryParse(input, out var timeSpan))
input = $"{dummyDate.Date.ToShortDateString()} {input}";
return DateTime.Parse(input);
}
Output:
01.01.1970 15:00:00
01.01.1970 15:00:22
09.12.2018 15:00:00
Depends on your localization:-)
I want to parse string date to DateTime but ignoring time.
My expected date format is M/d/yyyy which is 3/29/2018 (without leading zero).
The thing is string can be with or without time part and time can have different formats that I will not predict.
var inputDateString = "12/31/2017 12:00:00 AM" // false, but I want to parse
var inputDateString = "12/31/2017" // true
DateTime.TryParseExact(inputDateString, "M/d/yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out var parsedDate);
Is there any way to parse date string having only specific date format and ignore time?
There is an overload to TryParseExact that allows you to pass in multiple formats. If you know in advance which formats to expect, you can use this overload:
void Main()
{
string[] validFormats = {"M/d/yyyy", "M/d/yyyy hh:mm:ss tt"};
var inputDateString1 = "12/31/2017 12:00:00 AM"; // false, but I want to parse
var inputDateString2 = "12/31/2017"; // true
DateTime.TryParseExact(inputDateString1, validFormats, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt1);
DateTime.TryParseExact(inputDateString2, validFormats, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt2);
}
You can then get only the date portion using the Date property.
You could strip the time part from the input string, or parse the full input, using only the .Datepart.
var parsedDate = DateTime.MinValue;
var inputDateString = "12/31/2017 12:00:00 AM"; // false, but I want to parse
// option 1: use only the date part
if (DateTime.TryParseExact((inputDateString ?? "").Split(' ')[0] , "M/d/yyyy",
CultureInfo.InvariantCulture, DateTimeStyles.None, out parsedDate))
Console.WriteLine(parsedDate);
// option 2: use the full input, but ignore the time
if (DateTime.TryParseExact(inputDateString, "M/d/yyyy hh:mm:ss tt",
CultureInfo.InvariantCulture, DateTimeStyles.None, out parsedDate))
Console.WriteLine(parsedDate.Date);
Personally, I would go with the first option.
If you always want to only parse the Date portion that can be done by explicitly ensuring the string is only 10 characters in length. This is a somewhat convoluted example but you can strip out what you don't need, you'll get the idea:
var inputDateString = "12/31/2017 12:00:00 AM";
string datePortion = string.Empty;
DateTime dt;
if (inputDateString.Length>10)
{
// take first 10 characters of inputDateString
datePortion = inputDateString.Substring(0, Math.Min(inputDateString.Length, 10));
}
else if (inputDateString.Length==10)
{
// inputDateString is already 10 characters
datePortion = inputDateString;
}
else
{
// inputDateString is less than 10 characters, no date found, do nothing.
}
if(!DateTime.TryParse(datePortion, out dt))
{
// handle error that occurred,
}
else
{
// parse was successful, carry on.
}
Using ASP.NET Forms, I'm encountering a problem with converting a 12 hour time into a timespan. Below I'm combining DateTime with TimeSpan as the user chooses a date and then a time. The fields are controlled by javascript.
DateTime DateResult = DateTime.TryParse(txtDate.Text, out DateResult) ? DateResult : DateTime.Today;
TimeSpan TimeResult = TimeSpan.TryParseExact(txtTime.Text, "h:mm tt", CultureInfo.InvariantCulture, out TimeResult) ? TimeResult : new TimeSpan();
DateResult = DateResult.Add(TimeResult)
So parsing the date works fine, but Timespan doesn't. One example:
Date Entered: 08/03/2018
Time Entered: 3:00 AM
Values are gettined passed okay but time fails so DateResult becomes "08/03/2018 00:00" but not "08/03/2018 03:00". I have also tried using the method TimeSpan.TryParse but no luck with that one.
I've also made sure that the format is correct by manually entering the time in the database behind the scenes. The gridview has a column that shows the full date in this format "dd/MM/yyyy h:mm tt", and works.
Anyone please share some light? Ideally, I would like to avoid any third party plug-ins.
Parse them together
Simplest thing is to just concatenate the strings before parsing as a single DateTime, e.g.
var dateEntered = #"08/03/2018";
var timeEntered = #"3:00 am";
DateTime result;
var completeDateString = dateEntered + " " + timeEntered;
var ok = DateTime.TryParse(completeDateString, out result);
if (!ok) result = DateTime.Today;
Console.WriteLine(result);
Output:
8/3/2018 3:00:00 AM
Ta da
If you have to parse them separately
If you'd like to work with the fields separately, you still can (I guess you'd have to do this if you want the time format to be exact but the date portion to be flexible, as it is in your example). But TimeSpan.TryParseExact is really different from DateTime.Parse. The format codes are different; it doesn't support the ":" character (except as a literal with an escape, e.g. "\:"), for example, or the "tt" formatting specifier. I'm guessing the concept of am/pm has to do with an absolute point in time, not a relative time offset, so isn't provided for. But you can still parse the textbox as a DateTime and use its time portion.
You can probably shorten this a bit but this example gives you everything you need:
static public DateTime ParseDateTime(string input)
{
DateTime output;
var ok = DateTime.TryParse(input, out output);
if (ok) return output;
return DateTime.Today;
}
static public TimeSpan ParseTime(string input)
{
DateTime output;
var ok = DateTime.TryParseExact(input, #"h:mm tt", CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.NoCurrentDateDefault, out output);
return output.Subtract(output.Date);
}
public static void Main()
{
var dateEntered = #"08/03/2018";
var timeEntered = #"3:00 am";
DateTime dateResult = ParseDateTime(dateEntered);
TimeSpan timeResult = ParseTime(timeEntered);
DateTime finalResult = dateResult.Add(timeResult);
Console.WriteLine(finalResult);
}
Output:
8/3/2018 3:00:00 AM
Code on DotNetFiddle
See ParseExact or https://msdn.microsoft.com/en-us/library/system.timespan.tryparseexact(v=vs.110).aspx for TryParseExact should work for both DateTime as well as TimeSpan inter alia
Fyi it's called the meridian and see also AM/PM to TimeSpan
I have a value stored in variable of type System.TimeSpan as follows.
System.TimeSpan storedTime = 03:00:00;
Can I re-store it in another variable of type String as follows?
String displayValue = "03:00 AM";
And if storedTime variable has the value of
storedTime = 16:00:00;
then it should be converted to:
String displayValue = "04:00 PM";
You can do this by adding your timespan to the date.
TimeSpan timespan = new TimeSpan(03,00,00);
DateTime time = DateTime.Today.Add(timespan);
string displayTime = time.ToString("hh:mm tt"); // It will give "03:00 AM"
Very simple by using the string format
on .ToSTring("") :
if you use "hh" ->> The hour, using a 12-hour clock from 01 to 12.
if you use "HH" ->> The hour, using a 24-hour clock from 00 to 23.
if you add "tt" ->> The Am/Pm designator.
exemple converting from 23:12 to 11:12 Pm :
DateTime d = new DateTime(1, 1, 1, 23, 12, 0);
var res = d.ToString("hh:mm tt"); // this show 11:12 Pm
var res2 = d.ToString("HH:mm"); // this show 23:12
Console.WriteLine(res);
Console.WriteLine(res2);
Console.Read();
wait a second, there is a catch, the system Culture !!, the same code executed on windows set to different language
especially with different culture language will generate different result.
for example in windows set to Arabic language the result Will be like this :
// 23:12 م
م means Evening (first letter of مساء) .
in windows set to German language i think it will show // 23:12 du.
you can change between different format on windows control panel under windows regional and language -> current format (combobox) and change... apply it, do a rebuild (execute) of your app and watch what i'm talking about.
so how can you force showing Am and Pm prefix in English event if the culture of the current system isn't set to English ?
easy just by adding two lines ->
the first step add using System.Globalization; on top of your code
and modify the previous code to be like this :
DateTime d = new DateTime(1, 1, 1, 23, 12, 0);
var res = d.ToString("HH:mm tt", CultureInfo.InvariantCulture); // this show 11:12 Pm
InvariantCulture => using default English Format.
another question I want to have the pm to be in Arabic or specific language, even if I use windows set to English (or other language) regional format?
Solution for Arabic Exemple :
DateTime d = new DateTime(1, 1, 1, 23, 12, 0);
var res = d.ToString("HH:mm tt", CultureInfo.CreateSpecificCulture("ar-AE"));
this will show // 23:12 م
event if my system is set to English region format.
you can change "ar-AE" if you want to another language format. there is a list for each language.
exemples :
ar ar-SA Arabic
ar-BH ar-BH Arabic (Bahrain)
ar-DZ ar-DZ Arabic (Algeria)
ar-EG ar-EG Arabic (Egypt)
.....
You can add the TimeSpan to a DateTime, for example:
TimeSpan span = TimeSpan.FromHours(16);
DateTime time = DateTime.Today + span;
String result = time.ToString("hh:mm tt");
Demo: http://ideone.com/veJ6tT
04:00 PM
Standard Date and Time Format Strings
Doing some piggybacking off existing answers here:
public static string ToShortTimeSafe(this TimeSpan timeSpan)
{
return new DateTime().Add(timeSpan).ToShortTimeString();
}
public static string ToShortTimeSafe(this TimeSpan? timeSpan)
{
return timeSpan == null ? string.Empty : timeSpan.Value.ToShortTimeSafe();
}
string displayValue="03:00 AM";
This is a point in time , not a duration (TimeSpan).
So something is wrong with your basic design or assumptions.
If you do want to use it, you'll have to convert it to a DateTime (point in time) first. You can format a DateTime without the date part, that would be your desired string.
TimeSpan t1 = ...;
DateTime d1 = DateTime.Today + t1; // any date will do
string result = d1.ToString("hh:mm:ss tt");
storeTime variable can have value like
storeTime=16:00:00;
No, it can have a value of 4 o'clock but the representation is binary, a TimeSpan cannot record the difference between 16:00 and 4 pm.
You will need to get a DateTime object from your TimeSpan and then you can format it easily.
One possible solution is adding the timespan to any date with zero time value.
var timespan = new TimeSpan(3, 0, 0);
var output = new DateTime().Add(timespan).ToString("hh:mm tt");
The output value will be "03:00 AM" (for english locale).
You cannot add AM / PM to a TimeSpan. You'll anyway have to associate the TimaSpan value with DateTime if you want to display the time in 12-hour clock format.
TimeSpan is not intended to use with a 12-hour clock format, because we are talking about a time interval here.
As it says in the documentation;
A TimeSpan object represents a time interval (duration of time or elapsed time) that is measured as a positive or negative number of days, hours, minutes, seconds, and fractions of a second. The TimeSpan structure can also be used to represent the time of day, but only if the time is unrelated to a particular date. Otherwise, the DateTime or DateTimeOffset structure should be used instead.
Also Microsoft Docs describes as follows;
A TimeSpan value can be represented as [-]d.hh:mm:ss.ff, where the optional minus sign indicates a negative time interval, the d component is days, hh is hours as measured on a 24-hour clock, mm is minutes, ss is seconds, and ff is fractions of a second.
So in this case, you can display using AM/PM as follows.
TimeSpan storedTime = new TimeSpan(03,00,00);
string displayValue = new DateTime().Add(storedTime).ToString("hh:mm tt");
Side note :
Also should note that the TimeOfDay property of DateTime is a TimeSpan, where it represents
a time interval that represents the fraction of the day that has elapsed since midnight.
To avoid timespan format limitations, convert to datetime.
Simplest expression would be:
// Where value is a TimeSpan...
(new DateTime() + value).ToString("hh:mm tt");
Parse timespan to DateTime and then use Format ("hh:mm:tt"). For example.
TimeSpan ts = new TimeSpan(16, 00, 00);
DateTime dtTemp = DateTime.ParseExact(ts.ToString(), "HH:mm:ss", CultureInfo.InvariantCulture);
string str = dtTemp.ToString("hh:mm tt");
str will be:
str = "04:00 PM"
You can try this:
string timeexample= string.Format("{0:hh:mm:ss tt}", DateTime.Now);
you can remove hh or mm or ss or tt according your need
where
hh is hour in 12 hr formate,
mm is minutes,ss is seconds,and tt is AM/PM.
Parse timespan to DateTime. For Example.
//The time will be "8.30 AM" or "10.00 PM" or any time like this format.
public TimeSpan GetTimeSpanValue(string displayValue)
{
DateTime dateTime = DateTime.Now;
if (displayValue.StartsWith("10") || displayValue.StartsWith("11") || displayValue.StartsWith("12"))
dateTime = DateTime.ParseExact(displayValue, "hh:mm tt", CultureInfo.InvariantCulture);
else
dateTime = DateTime.ParseExact(displayValue, "h:mm tt", CultureInfo.InvariantCulture);
return dateTime.TimeOfDay;
}
At first, you need to convert time span to DateTime structure:
var dt = new DateTime(2000, 12, 1, timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds)
Then you need to convert the value to string with Short Time format
var result = dt.ToString("t"); // Convert to string using Short Time format
Because this situation is as annoying as it is common... I created a helper class, which I have released in a NuGet package. This could be a private method and can be used in MVC views as well as in back-end C# code.
public static string AsTimeOfDay(TimeSpan timeSpan, TimeSpanFormat timeSpanFormat = TimeSpanFormat.AmPm)
{
int hours = timeSpan.Hours;
int minutes = timeSpan.Minutes;
string AmOrPm = "AM";
string returnValue = string.Empty;
if (timeSpanFormat == TimeSpanFormat.AmPm)
{
if (hours >= 12)
{
AmOrPm = "PM";
}
if (hours > 12)
{
hours -= 12;
}
TimeSpan timeSpanAmPm = new TimeSpan(hours, minutes, 0);
returnValue = timeSpanAmPm.ToString(#"h\:mm") + " " + AmOrPm;
}
else
{
returnValue = timeSpan.ToString(#"h\:mm");
}
return returnValue;
}