34

I'm converting C# date time to string. Later when I convert it back to DateTime object it appears that they are not equal.

const string FMT = "yyyy-MM-dd HH:mm:ss.fff";
DateTime now1 = DateTime.Now;
string strDate = now1.ToString(FMT);
DateTime now2 = DateTime.ParseExact(strDate, FMT, CultureInfo.InvariantCulture);
Console.WriteLine(now1.ToBinary());
Console.WriteLine(now2.ToBinary());

Here is the example. Looks like everything is included in string format, when I print date both displays the same, but when I compare objects or print date in binary format I see the difference. It looks strange to me, could you please explain what is going on here?

Here is the output for the code above.

-8588633131198276118
634739049656490000
axe
  • 2,331
  • 4
  • 31
  • 53
  • Small point: if you're going to parse the string using `InvariantCulture`, then you probably want to pass `InvariantCulture` into the ToString method as well, just to be safe: `now1.ToString(FMT, CultureInfo.InvariantCulture);` – Dr. Wily's Apprentice May 29 '12 at 12:41

5 Answers5

47

You should use the roundtrip format specifier "O" or "o" if you want to preserve the value of the DateTime.

The "O" or "o" standard format specifier represents a custom date and time format string using a pattern that preserves time zone information. For DateTime values, this format specifier is designed to preserve date and time values along with the DateTime.Kind property in text. The formatted string can be parsed back by using the DateTime.Parse(String, IFormatProvider, DateTimeStyles) or DateTime.ParseExact method if the styles parameter is set to DateTimeStyles.RoundtripKind.

Using your code (apart from changing the format string):

const string FMT = "O";
DateTime now1 = DateTime.Now;
string strDate = now1.ToString(FMT);
DateTime now2 = DateTime.ParseExact(strDate, FMT, CultureInfo.InvariantCulture);
Console.WriteLine(now1.ToBinary());
Console.WriteLine(now2.ToBinary());

I get:

-8588633127598789320
-8588633127598789320
Oded
  • 489,969
  • 99
  • 883
  • 1,009
19

Oded's answer is good but it didn't work for me for UTC dates. In order to get it to work for UTC dates, I needed to specify a DateTimeStyles value of "RoundtripKind" so that it didn't try to assume it was a local time. Here is the updated code from above:

const string FMT = "O";
DateTime now1 = DateTime.Now;
string strDate = now1.ToString(FMT);
DateTime now2 = DateTime.ParseExact(strDate, FMT, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind);
Console.WriteLine(now1.ToBinary());
Console.WriteLine(now2.ToBinary());

Note, this works for both UTC and local dates.

Taylor Lafrinere
  • 3,084
  • 18
  • 27
2

2 things:

  1. You can use the ParseExact overload that takes a DateTimeStyle parameter in order to specify AssumeLocal.

  2. There will still be a small difference between now1 and now2 unless you increase the precision to 7 digits instead of 3: "yyyy-MM-dd HH:mm:ss.fffffff"

        const string FMT = "yyyy-MM-dd HH:mm:ss.fffffff";
        DateTime now1 = DateTime.Now;
        string strDate = now1.ToString(FMT);
        DateTime now2 = DateTime.ParseExact(strDate, FMT, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal);
        Console.WriteLine(now1.ToBinary());
        Console.WriteLine(now2.ToBinary());
    

Even without the above changes, the calculated difference between now1 and now2 appears small, even though the binary values do not appear similar.

        TimeSpan difference = now2.Subtract(now1);
        Console.WriteLine(difference.ToString());
Dr. Wily's Apprentice
  • 10,212
  • 1
  • 25
  • 27
  • Thanks. I need to get exactly the same value, any difference would cause unit test failure, so it's better to use "O" instead. – axe May 30 '12 at 07:37
2

If you dont need the string to be human-readable (like, you want to cipher it before storage), you can just call string str = dt1.ToBinary().ToString(); and DateTime dt2 = DateTime.FromBinary(long.Parse(str));

DateTime now1 = DateTime.Now;
string strDate = now1.ToBinary().ToString();
DateTime now2 = DateTime.FromBinary(long.Parse(strDate));
Console.WriteLine(now1.ToBinary());
Console.WriteLine(now2.ToBinary());
Jan 'splite' K.
  • 1,667
  • 2
  • 27
  • 34
-2

Just use this code it convert date time to string and string to date time

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace DateTimeConvert
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
              label1.Text = ConvDate_as_str(textBox1.Text);
        }

        public string ConvDate_as_str(string dateFormat)
        {
            try
            {
                char[] ch = dateFormat.ToCharArray();
                string[] sps = dateFormat.Split(' ');
                string[] spd = sps[0].Split('.');
                dateFormat = spd[0] + ":" + spd[1] + " " + sps[1];
                DateTime dt = new DateTime();
                dt = Convert.ToDateTime(dateFormat);
                return dt.Hour.ToString("00") + dt.Minute.ToString("00");
            }
            catch (Exception ex)
            {
                return "Enter Correct Format like <5.12 pm>";
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            label2.Text = ConvDate_as_date(textBox2.Text);
        }

        public string ConvDate_as_date(string stringFormat)
        {
            try
            {
                string hour = stringFormat.Substring(0, 2);
                string min = stringFormat.Substring(2, 2);
                DateTime dt = new DateTime();
                dt = Convert.ToDateTime(hour+":"+min);
                return String.Format("{0:t}", dt); ;
            }
            catch (Exception ex)
            {
                return "Please Enter Correct format like <0559>";
            }
        }
    }
}
Jonathan Gilbert
  • 3,526
  • 20
  • 28