content: /**
   * DBSyncer Copyright 2020-2023 All Rights Reserved.
   */
  package org.dbsyncer.connector.mysql.deserializer;
  
  import com.github.shyiko.mysql.binlog.io.ByteArrayInputStream;
  
  import java.io.IOException;
  import java.io.Serializable;
  import java.sql.Timestamp;
  import java.time.LocalDateTime;
  
  public final class DatetimeV2Deserialize {
  
      public Serializable deserializeDatetimeV2(int meta, ByteArrayInputStream inputStream) throws IOException {
          long datetime = bigEndianLong(inputStream.read(5), 0, 5);
          int yearMonth = bitSlice(datetime, 1, 17, 40);
          int fsp = deserializeFractionalSeconds(meta, inputStream);
          LocalDateTime time = LocalDateTime.of(
                  yearMonth / 13,
                  yearMonth % 13,
                  bitSlice(datetime, 18, 5, 40),
                  bitSlice(datetime, 23, 5, 40),
                  bitSlice(datetime, 28, 6, 40),
                  bitSlice(datetime, 34, 6, 40),
                  fsp / 1000
          );
          return Timestamp.valueOf(time);
      }
  
      private long bigEndianLong(byte[] bytes, int offset, int length) {
          long result = 0;
          for (int i = offset; i < (offset + length); i++) {
              byte b = bytes[i];
              result = (result << 8) | (b >= 0 ? (int) b : (b + 256));
          }
          return result;
      }
  
      private int deserializeFractionalSeconds(int meta, ByteArrayInputStream inputStream) throws IOException {
          int length = (meta + 1) / 2;
          if (length > 0) {
              int fraction = bigEndianInteger(inputStream.read(length), 0, length);
              return fraction * (int) Math.pow(100, 3 - length);
          }
          return 0;
      }
  
      private int bigEndianInteger(byte[] bytes, int offset, int length) {
          int result = 0;
          for (int i = offset; i < (offset + length); i++) {
              byte b = bytes[i];
              result = (result << 8) | (b >= 0 ? (int) b : (b + 256));
          }
          return result;
      }
  
      private int bitSlice(long value, int bitOffset, int numberOfBits, int payloadSize) {
          long result = value >> payloadSize - (bitOffset + numberOfBits);
          return (int) (result & ((1 << numberOfBits) - 1));
      }
  
  }