Cannot convert Date received from PayPal to UTC date using C# - c#

In my ASP.Net app, I am receiving a date string from PayPal and when I try to convert it to UTC date it always fails. I have tried this conversion in LINQPad tool but I always get that the date string could not be successfully parsed.
The date string that my ASP.Net page receives from PayPal is like this: 08:45:29 May 25, 2016 PDT
Question: How can I successfully convert the PayPal received date to UTC date in C#? The code that I have tried so far is given below.
Code in LINQPad for conversion of PayPal date to UTC date
string payPalDateString = "08:45:29 May 25, 2016 PDT";
DateTime date = DateTime.Now;
if( DateTime.TryParse(payPalDateString, out date) == true) {
"payPalDateString was successfully parsed".Dump();
DateTime dateUTC = date.ToUniversalTime();
dateUTC.Dump("payPalDateString in UTC is as below");
} else {
payPalDateString.Dump("payPalDateString was NOT successfully parsed");
}
PayPal documentation says the following about the date it sends.
Time/Date stamp generated by PayPal, in the following format: HH:MM:SS DD Mmm YY, YYYY PST
The above date format mentioned in PayPal documentation should actually have been: HH:mm:ss MMM dd, yyyy PST

Please refer to the below logic to parse the DateTime exactly the way it was coming from Paypal
DateTime newDate;
DateTime.TryParseExact("08:45:29 May 25, 2016 PDT",
"HH:mm:ss MMM dd, yyyy PDT",
CultureInfo.InvariantCulture,
DateTimeStyles.None, out newDate);
var utcDateTime = newDate.ToUniversalTime();
I have added dotnetfiddle code
Since OP is not sure about the incoming time zone format to be in PDT, he was suggested to dynamically substitute time zone in the conversion format. He came up with this logic.
String.Format("HH:mm:ss MMM dd, yyyy {0}",
payPalDateString.Substring(payPalDateString.Length - 3))
Please note that there could be a number of other alternative ways to substitute the time zone at run time. This solution doesn't cover any error handling like if the input string doesn't come up with any time zone!!

Is you want to be able to support, say PST and PDT in your strings, I would create some sort of mapping from the abbreviations to an offset. Time zone abbreviations are not unique so you will need to include only the ones that are relevant to your data (and hope that PayPal doesn't use non-unique offsets like CST). You could start with what you know and add more as necessary:
Dictionary<string, string> TimeZones = new Dictionary<string, string>
{
{"PST", "-08:00"},
{"PDT", "-07:00"},
// more as needed
};
string s = "08:45:29 May 25, 2016 PDT";
StringBuilder sb = new StringBuilder(s);
foreach(var kvp in TimeZones)
sb = sb.Replace(kvp.Key,kvp.Value);
s = sb.ToString();
DateTime dt;
bool success = DateTime.TryParseExact(s,
"HH:mm:ss MMM dd, yyyy zzz",
CultureInfo.InvariantCulture,
DateTimeStyles.AdjustToUniversal,
out dt);

Related

Parsing date form dd-MM-yyyy to dd MMM yyyy

I want to parse dd-MM-yyyy date format into dd MMM yyyy I get the reference but it cannot convert date in a proper manner it mismatches the date and month.
Suppose my date is
string dat = "11-01-2019"
and I am using
string date = DateTime.Parse(dat).ToString("dd MMM yyyy");
but it returns 01 Nov 2019. But actually, it is 11 Jan 2019 because the format of date is dd-MM-yyyy I don't understand how to correct it any method of parsing I am using it returns 01 Nov 2019 that is wrong. Please help me to resolve the issue
You'll need to specify the culture the date is formatted for. I'm assuming UK here:
var ukCulture = System.Globalization.CultureInfo.GetCultureInfo("en-gb");
string dat = "11-01-2019";
string date = DateTime.Parse(dat, ukCulture).ToString("dd MMM yyyy");
Console.WriteLine(date);
Try it online
Note that you'll get a FormatException if you enter an invalid date here, so it might be better to use TryParse:
var ukCulture = System.Globalization.CultureInfo.GetCultureInfo("en-gb");
string dat = "11-01-2019";
DateTime parsedDate;
if (DateTime.TryParse(dat, ukCulture, System.Globalization.DateTimeStyles.None, out parsedDate))
{
string date = parsedDate.ToString("dd MMM yyyy");
Console.WriteLine(date);
}
else
{
Console.WriteLine("invalid date");
}
Try it online
Adding to John's great answer, here's a list of CultureInfo codes for reference:
http://www.csharp-examples.net/culture-names/

convert date time to format ddd MM/dd/yyyy HH:mm:ss

In the below code snippet I'am passing string value "item.Date" to string "Date"
I wanted to convert it to this format ddd MM/dd/yyyy HH:mm:ss.
converting to string and as well the above format was not going well i guess.
I tried using:
DateTime dateformatted = DateTime.ParseExact(item.Date, "ddd dd MMM yyyy h:mm tt", null);
it showed error. Can anyone help
foreach (var item in data)
{
model.Add(new MailDetailDTO
{
Attributes = item.Attribute1,
Date = item.Date,
From = item.SentFrom,
FromOrg = item.OrganizationName,
IsConfidential = item.IsConfidential,
MailID = item.MailHeaderID,
}
}
This is what the ParseExact API documentation on MSDN has to say :
The format of the string representation must match the specified
format exactly.
This means that there is a certain mismatch in the format you have stored the date time value in item.Date string property and the custom date time format ddd dd MMM yyyy h:mm tt which you're passing as argument to ParseExact API.
Have a look at the below code snippet:
private static void DateTimeForatError()
{
var item = "Sun 22-May-2016 3:52 AM";
DateTime dateformatted = DateTime.ParseExact(item, "ddd dd MMM yyyy h:mm tt", null); //results in exception
}
Date time string value present in item variable looks parseable but the next line results in String was not recognized as a valid DateTime. error. That is because I'm using - hyphen as the delimiter for day, month and year while the custom format string dd MMM yyyy uses space . As long as there is even a single difference in the way I have stored date time string value in item variable which is not complying with the custom format string ddd dd MMM yyyy h:mm tt it will burst. The moment I make the value of item to Sun 22 May 2016 3:52 AM it succeeds. You just change the value of item.Date in the object of MailDetailDTO object to match it with the custom date time string format to get rid of the error OR change the custom date time format string that you are passing to the PraseExact API to match it with the format of date time value coming in item.Date from your back-end data.

mono: DateTimeOffset.TryParseExact works on full .NET but not on debian

My C# project is taking xml and extracting pertinent data, one of which pieces is a date time value. The following code works correctly on my desktop running Win8.1 and .NET4. However when I run it through mono, it's failing to parse the data.
using glob = System.Globalization;
DateTimeOffset dt = DateTimeOffset.MinDate;
string[] fmts = new string[]
{
"MMM dd, yyyy hh:mm tt EDT",
"MMM dd, yyyy hh:mm tt EST",
"MMM dd, yyyy hh:mm tt CDT",
"MMM dd, yyyy hh:mm tt CST",
"MMM dd, yyyy hh:mm tt MDT",
"MMM dd, yyyy hh:mm tt MST",
"MMM dd, yyyy hh:mm tt AKST",
"MMM dd, yyyy hh:mm tt AKDT",
"MMM dd, yyyy hh:mm tt HST",
"MMM dd, yyyy hh:mm tt PST",
"MMM dd, yyyy hh:mm tt PDT"
};
var dtString = z.Substring(pos1 + 5, pos2 - pos1 - 1 - 5).Replace("ft", "").Trim();
dtString = dtString.Substring(0, 1).ToUpper() + dtString.Substring(1);
dtString = dtString.Substring(0, dtString.Length - 7)
+ dtString.Substring(dtString.Length - 7).ToUpper();
DateTimeOffset.TryParseExact(dtString, fmts,
glob.CultureInfo.InvariantCulture, glob.DateTimeStyles.None, out dt);
To check if the conversion worked ok, I do this:
if (dt == DateTimeOffset.MinDate)
Console.WriteLine("failed to convert dt = MinValue -> " + dtString);
Here's an example of the data string being processed:
raw: mar 21, 2015 10:30 am cdt
after my formatting: Mar 21, 2015 10:15 AM CDT
It's not specific to the CDT tz - I get the same issue for all timezones.
When I run $ date on the Linux box, it's reporting the same date, time and tz as my desktop, in this format (Mon Mar 23 11:31:16 EDT 2015).
The section is wrapped in a try/catch, but no exceptions are being thrown (also have Console output in there).
I can code around it by changing the string around before TryParse, but it would seem this method was designed so that this is not necessary.
Is this a bug (or am I missing something)? If so where does one report them?
Thanks
A few points:
In the code you posted, the part where you manipulate the dtString variable is meaningless to us, because you didn't include values for pos1 or pos2. It seems quite messy, and in general - that sort of manipulation should be avoided if possible. I'm not sure what it has to do with your question, if anything.
You are using the TryParseExact method, which returns a boolean true on success - so the comparison check is unnecessary. (Also, the field is called MinValue, not MinDate)
Time zone abbreviations are not valid in format strings. The letters in the string could be confused with actual custom formatting values. If you wanted to exclude them, you would place them in single-tick or double-tick quotation marks.
In general, time zone abbreviations should not be used for input. There are just too many ambiguities. For example, this list of abbreviations shows 5 possible interpretations of "CST".
The parsers that come with the DateTime and DateTimeOffset types do not understand time zone abbreviations at all. You claim it works fine on your desktop under .NET 4, but I call BS.
As you can see, it did not interpret the offset as CDT (-05:00). Instead it took the local time zone from my computer, which happens to be PDT (-07:00).
The correct way to deal with this is to parse the date input as a DateTime, then use some other mechanism to determine the offset. If you MUST use the time zone abbreviation, and you are absolutely sure you only have the time zones you showed above, and they're all from the united states, then it would go something like this:
// define the list that you care about
private static readonly Dictionary<string, TimeSpan> Abbreviations = new Dictionary<string, TimeSpan>
{
{"EDT", TimeSpan.FromHours(-4)},
{"EST", TimeSpan.FromHours(-5)},
{"CDT", TimeSpan.FromHours(-5)},
{"CST", TimeSpan.FromHours(-6)},
{"MDT", TimeSpan.FromHours(-6)},
{"MST", TimeSpan.FromHours(-7)},
{"PDT", TimeSpan.FromHours(-7)},
{"PST", TimeSpan.FromHours(-8)},
{"AKDT", TimeSpan.FromHours(-8)},
{"AKST", TimeSpan.FromHours(-9)},
{"HST", TimeSpan.FromHours(-10)}
};
static DateTimeOffset ParseInput(string input)
{
// get just the datetime part, without the abbreviation
string dateTimePart = input.Substring(0, input.LastIndexOf(" ", StringComparison.Ordinal));
// parse it to a datetime
DateTime dt;
bool success = DateTime.TryParseExact(dateTimePart, "MMM dd, yyyy hh:mm tt",
CultureInfo.InvariantCulture, DateTimeStyles.None, out dt);
// handle bad input
if (!success)
{
throw new ArgumentException("Invalid input string.", "input");
}
// get the abbreviation from the input string
string abbreviation = input.Substring(input.LastIndexOf(" ", StringComparison.Ordinal) + 1)
.ToUpperInvariant();
// look up the offset from the abbreviation
TimeSpan offset;
success = Abbreviations.TryGetValue(abbreviation, out offset);
if (!success)
{
throw new ArgumentException("Unknown time zone abbreviation.", "input");
}
// apply the offset to the datetime, and return
return new DateTimeOffset(dt, offset);
}
Now it will return the correct output:
string dtString = "Mar 21, 2015 10:15 AM CDT";
DateTimeOffset dto = ParseInput(dtString);
Console.WriteLine(dto);
Also note that if you were really trying to cover all legal US time zones, you should also consider adding HAST, HADT, CHST, SST, and AST to the list.

C# DateTime Formatting Names

What is the name of this DateTime format:
Tue Apr 01 2014 00:00:00 GMT+0100 (GMT Daylight Time)
Is there anyway I could detect this format in code?
The reason I am asking is that I have a function with DateTime parameter, which comes in different formats, and I would like to detect the format type or name; so that I could convert them accorddingly to the simple format of dd/MM/yyyy hh:mm:ss.
The other second format I am getting is this: 2014-03-31T23:00:00.000Z.
Many thanks.
Edit
I wrote this function to convert from Tue Apr 01 2014 00:00:00 GMT+0100 (GMT Daylight Time) to dd/MM/yyyy hh:mm:ss. This function fails when the input is of type 2014-03-31T23:00:00.000Z.
I wonder how could possibly identify the type of parameter coming and convert accordingly?
public static DateTime ConvertDateObjectToDateTime(string dateToConvert)
{
var value = new DateTime();
if (!string.IsNullOrEmpty(dateToConvert))
{
int gmtIndex = dateToConvert.IndexOf("G", System.StringComparison.Ordinal);
string newDate = dateToConvert.Substring(0, gmtIndex).Trim();
value = DateTime.ParseExact(newDate, "ddd MMM dd yyyy HH:mm:ss", CultureInfo.InvariantCulture);
return value;
}
return value;
}
The second is definitely UTC, however, the first could be UTC + offset or it could be Local + offset (it looks like the latter the more I examine it). The best tool you have in your armoury for parsing specific dates is the ParseExact method.
Based on your edit, I am concerned about the fact you are ignoring the timezone information. You are assuming at this point that the date is already UTC (which it may not be) and just parsing/treating it as is...
However, to answer your particular question
I wonder how could possibly identify the type of parameter coming and convert accordingly?
You don't actually need to do that, ParseExact has an overload which allows you to specify multiple formats
value = DateTime.ParseExact(newDate,
new[] { "ddd MMM dd yyyy HH:mm:ss", "yyyy-MM-dd'T'HH:mm:ss.fff'Z'" },
CultureInfo.InvariantCulture,
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);

Convert date from MMM DD, YYYY to mm/dd/yy

i got date in my db in the form of MMM DD,YYYY
String thisDate1 = "Jan 05, 2009";
in order to get arithmetic operations such as add days i have to change it to standard format i.e mm/dd/yy. how can i do this. please help
Your string is fine as-is, you can use DateTime.Parse to convert it to a DateTime object which you can do your arithmetic on, like so:
var thisDate = DateTime.Parse(thisDate1);
var nextDate = thisDate.AddDays(1);
var nextDateAsString = nextDate.ToString("MMM dd, yyyy");
Also be careful with your casing, your current string is actually in MMM dd, yyyy format. DD would actually give you the letters DD themselves, as would YYYY. mm is minutes, while MM is for months. You can find more details on this on MSDN.
Also, as #HansPassant pointed out, you don't want to be storing your dates in a string until the last possible moment.

Categories

Resources