[DB2] เมื่อ DateTimeOffSet ของ C# ไม่สามารถจัดเก็บตรงๆได้ใน DB2

พอดีได้เข้ามาชวยแก้ปัญหาของน้องในทีมครับ เนื่องจากไปเจอว่า Library ที่ตั้ง Schedule ของ C# มันต้องการ Parameter ที่เป็น DateTimeOffSet แต่ DataType นี้ มีนดันใช้งานได้กับ MS SQL Server เท่านั้นครับ

กลับมาดูที่ DateTimeOffSet ดีกว่า มันเก็บอะไรบ้าง โดยแบ่งได้ 2 ส่วนครับ

  • DateTime พวก วันที่ และเวลา หรือ ถ้ามองโดยทั่วไป คือ TIMESTAMP ครับ
  • OffSet พวก TimeZone บอกโซนเวลา เช่น GMT +7 เป็นของ Bangkok ครับ

พอรู้จัก DateTimeOffset แล้ว และนำ Code ชุดเดียวกันมาทดสอบใช้งานตัว Dapper มัน Error ขึ้นครับ เนื่องจากไม่สามารถ Mapping C# Data Type DateTimeOffSet กับ DB2 Data Type ได้ครับ พอลองไปศึกษา DB2 ตัว Data Type ที่เหมาะสม คือ TIMESTAMP แต่ปัญหา คือ ว่า เวอร์ชันที่ผมใช้งานอยู่ DB2 11.5.4 for Linux มีแต่ TIMESTAMP แต่ไม่มี TIME ZONE ถ้าใน DB2 ต้องดูจาก Keyword TIMESTAMP WITH TIME ZONE ซึ่งมีแล้วในเวอร์ชัน Db2® for z/OS คงอีกสักพักที่ทาง DB2 Port ลงมาให้ Windows / Linux ใช้งานครับ

ทุกปัญหามีทางแก้ครับ !!!


ในเมื่อ DB2 มันไม่รู้จัก TIMESTAMP + TIMEZONE แนวทางการแก้่ไข มี 2 วิธีครับ

  • วิธีแรก : เก็บ DateTimeOffSet เป็น String ลง Database เลยครับ เวลา SELEECT / INSERT / UPDATE ต้องแปลง DataType กลับไปมาระหว่าง String <> DateTimeOffSet ครับ แต่วิธีนี้มีข้อเสียอย่างนึง มันจะ WHERE / ORDER ลำบากครับ เพราะเก็บเป็น String ครับ ถ้าอนาคต Table นี้ โตขึ้นเรื่อยๆ จะเจอปัญหา Performance ได้ครับ
  • วิธีสอง : แยก Column การเก็บ DateTime กับ OffSet (TimeZone) ออกจากกันครับ
    • ตอน SELECT มาต้องเอา DateTime + OffSet เพื่อทำ DateTimeOffSet
    • ตอน INSERT / UPDATE ต้องแยก DateTimeOffSet ออกมาเป็น DateTime / OffSet
    • สำหรับวิธีนี้ตัว Application เวลา Query ตาม DateTime สามารถทำได้รวดเร็วครับ แต่ต้่องมี Step มารองในส่วนของ OffSet อีกรอบครับ

สำหรับผมแล้ว ผมเลือกวิธีที่สองครับ โดยสามารถดู DTO ของ C# ที่แก้ไขแล้วได้เลยครับ

[JsonProperty("UpdatedDateRaw")]
public DateTime UpdatedDateRaw { get; set; }

[JsonProperty("UpdatedDateOffset")]
public string UpdatedDateOffset { get; set; }

[NotIn] //บอกให้ Dapper รู้ว่า Column นี้ไม่มีใน Database
[JsonProperty("UpdatedDate")]
public DateTimeOffset UpdatedDate
{
   get
   {
      //3. ตอนดึงค่าเอาไปใช้ ให้เอา OffSet เป็น String แปลงเป็น TimeSpan
      TimeSpan ts = TimeSpan.Parse(UpdatedDateOffset.Replace("+", ""));
      //4. เอา DateTime + TimeSpan ให้ได้เป็น DateTimeOffset
      DateTimeOffset result = new DateTimeOffset(UpdatedDateRaw, ts);
      return result;
   }
   set
   {
      //1. ดึง DateTime (DB2 TIMESTAMP) ออกมาจาก DateTimeOffSet 
      UpdatedDateRaw = Convert.ToDateTime(value.DateTime.ToString("yyyy-MM-dd HH:mm:ss.ffffff"));
      //2. ดึง OffSet (TimeZone) ออกมาจาก DateTimeOffSet 
      UpdatedDateOffset = value.ToString().Substring(value.ToString().Length - 6);
   }
}

กลับมาดู Table ของ DB2 มี SQL ประมาณนี้ครับ

CREATE TABLE INVEST.SCHED_SCHEDULE (
     SCHEDULEID	INTEGER	NOT NULL
  ,  NAME	VARCHAR(200)	NOT NULL
     --เอาส่วนนี้เทียบกับ Code C#
  ,  UPDATEDDATERAW TIMESTAMP
  , UPDATEDDATEOFFSET VARCHAR(10) NOT NULL
    --เอาส่วนนี้เทียบกับ Code C#
  ) 

Discover more from naiwaen@DebuggingSoft

Subscribe to get the latest posts to your email.