package model import ( "fmt" "time" ) // Protocol 定义协议结构 type Protocol struct { RawData []byte } // NewProtocol 创建新的协议实例 func NewProtocol(data []byte) *Protocol { return &Protocol{ RawData: data, } } // IdentifyTxType 解析传输类型(第一个字节,bit 0-7) func (p *Protocol) IdentifyTxType() (binary string, hexVal string, decVal uint8) { if len(p.RawData) == 0 { return "", "", 0 } // 获取第一个字节 firstByte := p.RawData[0] // 转换为二进制字符串(8位) binary = fmt.Sprintf("%08b", firstByte) // 转换为十六进制字符串 hexVal = fmt.Sprintf("%02X", firstByte) // 十进制值 decVal = firstByte return binary, hexVal, decVal } // IDParts 存储ID的三个部分 type IDParts struct { HSB struct { Binary string Hex string Dec uint8 } MSB struct { Binary string Hex string Dec uint8 } LSB struct { Binary string Hex string Dec uint8 } Complete struct { Binary string Hex string Dec uint32 } } // GetCompleteID 获取完整的24-bit ID code // HSB: bit 168-175 (索引21) // MSB: bit 176-183 (索引22) // LSB: bit 8-15 (索引1) func (p *Protocol) GetCompleteID() (*IDParts, error) { if len(p.RawData) < 23 { // 确保有足够的数据 return nil, fmt.Errorf("insufficient data length") } result := &IDParts{} // 处理 HSB (bit 168-175, 索引21) hsbByte := p.RawData[21] result.HSB.Binary = fmt.Sprintf("%08b", hsbByte) result.HSB.Hex = fmt.Sprintf("%02X", hsbByte) result.HSB.Dec = hsbByte // 处理 MSB (bit 176-183, 索引22) msbByte := p.RawData[22] result.MSB.Binary = fmt.Sprintf("%08b", msbByte) result.MSB.Hex = fmt.Sprintf("%02X", msbByte) result.MSB.Dec = msbByte // 处理 LSB (bit 8-15, 索引1) lsbByte := p.RawData[1] result.LSB.Binary = fmt.Sprintf("%08b", lsbByte) result.LSB.Hex = fmt.Sprintf("%02X", lsbByte) result.LSB.Dec = lsbByte // 组合完整的24位ID completeID := uint32(hsbByte)<<16 | uint32(msbByte)<<8 | uint32(lsbByte) result.Complete.Binary = fmt.Sprintf("%024b", completeID) result.Complete.Hex = fmt.Sprintf("%06X", completeID) result.Complete.Dec = completeID return result, nil } // WindDirection 存储风向的三个部分 type WindDirection struct { DirH struct { Binary string // 4位二进制,格式为"000X",其中X是bit24 Value uint8 // 实际值 } DirM struct { Binary string // bit 16-19 Value uint8 } DirL struct { Binary string // bit 20-23 Value uint8 } Complete struct { Binary string // 完整的12位二进制 Value uint16 // 完整值 (Range: 0°- 359°, Invalid: 0x1FF) Degree float64 // 角度值 IsValid bool // 是否有效 } } // GetWindDirection 解析风向数据 // DIR_H: 4位 (000 + bit24) // DIR_M: bit 16-19 // DIR_L: bit 20-23 // Value in hex (Range: 0°- 359°) // If invalid fill with 0x1FF func (p *Protocol) GetWindDirection() (*WindDirection, error) { if len(p.RawData) < 4 { // 确保有足够的数据 return nil, fmt.Errorf("insufficient data length") } result := &WindDirection{} // 获取包含bit24的字节(索引3) byte3 := p.RawData[3] // 获取bit24(字节的最低位) bit24 := byte3 & 0x01 // 构造DIR_H: "000" + bit24 result.DirH.Binary = fmt.Sprintf("000%d", bit24) result.DirH.Value = bit24 // 获取包含bit16-23的字节(索引2) byte2 := p.RawData[2] // 获取DIR_M (bit 16-19) dirM := (byte2 >> 4) & 0x0F result.DirM.Binary = fmt.Sprintf("%04b", dirM) result.DirM.Value = dirM // 获取DIR_L (bit 20-23) dirL := byte2 & 0x0F result.DirL.Binary = fmt.Sprintf("%04b", dirL) result.DirL.Value = dirL // 组合完整的风向值(12位) completeDir := (uint16(bit24) << 8) | (uint16(dirM) << 4) | uint16(dirL) result.Complete.Binary = fmt.Sprintf("%012b", completeDir) result.Complete.Value = completeDir // 检查值是否在有效范围内 (0-359) if completeDir > 359 { result.Complete.Value = 0x1FF result.Complete.IsValid = false result.Complete.Degree = 0 } else { result.Complete.IsValid = true result.Complete.Degree = float64(completeDir) } return result, nil } // WindSpeed 存储风速的各个部分 type WindSpeed struct { WspFlag struct { Binary string // bit 25 Value bool // true = 9bit模式, false = 10bit模式 } Extend struct { Binary string // 9bit模式: 000 + bit27 // 10bit模式: 00 + bit26 + bit27 Value uint8 } WspH struct { Binary string // bit 48-51 Value uint8 } WspL struct { Binary string // bit 52-55 Value uint8 } Complete struct { Binary string // 完整的9位或10位二进制 RawValue uint16 // 原始值 Value float64 // 实际风速值 (计算公式: RawValue/8*0.51) } } // GetWindSpeed 解析风速数据 // WSP_FLAG: bit 25 // WIND_EXTEND: // - 当WSP_FLAG=1时:000 + bit27(9bit模式) // - 当WSP_FLAG=0时:0 + bit136 + bit26 + bit27(10bit模式) // // WIND_H: bit 48-51 // WIND_L: bit 52-55 // 实际风速计算公式: value/8*0.51 func (p *Protocol) GetWindSpeed() (*WindSpeed, error) { if len(p.RawData) < 18 { // 确保有足够的数据(需要读取到bit136) return nil, fmt.Errorf("insufficient data length") } result := &WindSpeed{} // 解析 WSP_FLAG (bit 25) byte3 := p.RawData[3] wspFlag := (byte3 >> 1) & 0x01 // bit 25 result.WspFlag.Binary = fmt.Sprintf("%d", wspFlag) result.WspFlag.Value = wspFlag == 1 // 获取bit26和bit27 bit26 := (byte3 >> 2) & 0x01 bit27 := (byte3 >> 3) & 0x01 // 获取bit136(在第17个字节的最高位) byte17 := p.RawData[17] bit136 := (byte17 >> 7) & 0x01 // 解析 WIND_H 和 WIND_L (byte6) byte6 := p.RawData[6] windH := (byte6 >> 4) & 0x0F windL := byte6 & 0x0F result.WspH.Binary = fmt.Sprintf("%04b", windH) result.WspH.Value = windH result.WspL.Binary = fmt.Sprintf("%04b", windL) result.WspL.Value = windL // 组合完整的风速值 var rawValue uint16 if result.WspFlag.Value { // 9bit模式:000 + bit27 + WIND_H + WIND_L rawValue = (uint16(bit27) << 8) | (uint16(windH) << 4) | uint16(windL) result.Complete.Binary = fmt.Sprintf("%09b", rawValue) } else { // 10bit模式:0 + bit136 + bit26 + bit27 + WIND_H + WIND_L extendBits := (uint16(0) << 3) | (uint16(bit136) << 2) | (uint16(bit26) << 1) | uint16(bit27) rawValue = (uint16(extendBits) << 8) | (uint16(windH) << 4) | uint16(windL) result.Complete.Binary = fmt.Sprintf("%010b", rawValue) } result.Complete.RawValue = rawValue // 计算实际风速值:value/8*0.51 result.Complete.Value = float64(rawValue) / 8.0 * 0.51 return result, nil } // Temperature 存储温度的三个部分 type Temperature struct { TmpH struct { Binary string // 3位二进制,格式为"0XXX",其中XXX是bit29-31 Value uint8 } TmpM struct { Binary string // bit 32-35 Value uint8 } TmpL struct { Binary string // bit 36-39 Value uint8 } Complete struct { Binary string // 完整的11位二进制 RawValue uint16 // 原始值(包含400的偏移) Value float64 // 实际温度值 (Range: -40.0°C -> 60.0°C) IsValid bool // 是否有效 } } // GetTemperature 解析温度数据 // TMP_H: 4位 (0 + bit29-31) // TMP_M: bit 32-35 // TMP_L: bit 36-39 // 温度计算公式:(RawValue-400)/10 // 示例: // 10.5°C = 0x1F9 (505-400)/10 = 10.5 // -10.5°C = 0x127 (295-400)/10 = -10.5 // 范围:-40.0°C -> 60.0°C // 无效值:0x7FF func (p *Protocol) GetTemperature() (*Temperature, error) { if len(p.RawData) < 5 { // 确保有足够的数据 return nil, fmt.Errorf("insufficient data length") } result := &Temperature{} // 获取包含bit29-31的字节(索引3) byte3 := p.RawData[3] // 直接获取bit29-31 (010) tmpHBits := byte3 & 0x07 // TMP_H 是 "0" + bit29-31 result.TmpH.Binary = fmt.Sprintf("0%03b", tmpHBits) result.TmpH.Value = tmpHBits // 获取包含bit32-39的字节(索引4) byte4 := p.RawData[4] // 获取TMP_M (bit 32-35),在byte4的高4位 tmpM := (byte4 >> 4) & 0x0F result.TmpM.Binary = fmt.Sprintf("%04b", tmpM) result.TmpM.Value = tmpM // 获取TMP_L (bit 36-39),在byte4的低4位 tmpL := byte4 & 0x0F result.TmpL.Binary = fmt.Sprintf("%04b", tmpL) result.TmpL.Value = tmpL // 组合完整的温度值 // 1. TMP_H (0 + bit29-31) 放在最高位 // 2. TMP_M (bit 32-35) 放在中间 // 3. TMP_L (bit 36-39) 放在最低位 completeTemp := uint16(0) completeTemp |= uint16(tmpHBits) << 8 // TMP_H 移到高8位 completeTemp |= uint16(tmpM) << 4 // TMP_M 移到中间4位 completeTemp |= uint16(tmpL) // TMP_L 在最低4位 result.Complete.Binary = fmt.Sprintf("%012b", completeTemp) result.Complete.RawValue = completeTemp // 检查温度是否在有效范围内 // 有效范围计算: // -40°C = (-40 * 10 + 400) = 0 // 60°C = (60 * 10 + 400) = 1000 if completeTemp > 1000 { // 超出范围 result.Complete.RawValue = 0x7FF // 无效值 result.Complete.Value = 0 result.Complete.IsValid = false } else { // 温度计算:(RawValue-400)/10 result.Complete.Value = (float64(completeTemp) - 400) / 10 result.Complete.IsValid = true } return result, nil } // Humidity 存储湿度的两个部分 type Humidity struct { HmH struct { Binary string // bit 40-43 Value uint8 } HmL struct { Binary string // bit 44-47 Value uint8 } Complete struct { Binary string // 完整的8位二进制 RawValue uint8 // 原始值(十六进制) Value uint8 // 实际湿度值 (Range: 1% - 99%) IsValid bool // 是否有效 } } // GetHumidity 解析湿度数据 // HM_H: bit 40-43 // HM_L: bit 44-47 // Range: 1% - 99% // If invalid fill with 0xFF // 示例:0x37 = 55% (3*16 + 7 = 55) func (p *Protocol) GetHumidity() (*Humidity, error) { if len(p.RawData) < 6 { // 确保有足够的数据(bit 47 在第6个字节内) return nil, fmt.Errorf("insufficient data length") } result := &Humidity{} // 获取包含bit40-47的字节(索引5) byte5 := p.RawData[5] // 获取HM_H (bit 40-43) hmH := (byte5 >> 4) & 0x0F result.HmH.Binary = fmt.Sprintf("%04b", hmH) result.HmH.Value = hmH // 获取HM_L (bit 44-47) hmL := byte5 & 0x0F result.HmL.Binary = fmt.Sprintf("%04b", hmL) result.HmL.Value = hmL // 原始十六进制值 result.Complete.Binary = fmt.Sprintf("%08b", byte5) result.Complete.RawValue = byte5 // 直接使用十六进制值转换为十进制作为湿度值 decimalValue := byte5 // 检查湿度是否在有效范围内 (1-99) if decimalValue < 1 || decimalValue > 99 { result.Complete.RawValue = 0xFF // 无效值 result.Complete.Value = 0 result.Complete.IsValid = false } else { result.Complete.Value = decimalValue result.Complete.IsValid = true } return result, nil } // GustSpeed 存储阵风速度数据 type GustSpeed struct { GustH struct { Binary string // bit 56-59 Value uint8 } GustL struct { Binary string // bit 60-63 Value uint8 } Complete struct { Binary string // 完整的8位二进制 RawValue uint8 // 原始值 Value float64 // 实际阵风速度值 (计算公式: RawValue*0.51) } } // GetGustSpeed 解析阵风速度数据 // GUST_H: bit 56-59 // GUST_L: bit 60-63 // 实际阵风速度计算公式: value*0.51 func (p *Protocol) GetGustSpeed() (*GustSpeed, error) { if len(p.RawData) < 8 { // 确保有足够的数据(bit 63 在第8个字节内) return nil, fmt.Errorf("insufficient data length") } result := &GustSpeed{} // 解析 GUST_H (bit 56-59) 和 GUST_L (bit 60-63) byte7 := p.RawData[7] gustH := (byte7 >> 4) & 0x0F gustL := byte7 & 0x0F result.GustH.Binary = fmt.Sprintf("%04b", gustH) result.GustH.Value = gustH result.GustL.Binary = fmt.Sprintf("%04b", gustL) result.GustL.Value = gustL // 组合完整的阵风速度值 rawValue := byte7 result.Complete.Binary = fmt.Sprintf("%08b", rawValue) result.Complete.RawValue = rawValue // 计算实际阵风速度值:value*0.51 result.Complete.Value = float64(rawValue) * 0.51 return result, nil } // Rainfall 存储降雨量数据 type Rainfall struct { RainHH struct { Binary string // bit 64-67 Value uint8 } RainHL struct { Binary string // bit 68-71 Value uint8 } RainLH struct { Binary string // bit 72-75 Value uint8 } RainLL struct { Binary string // bit 76-79 Value uint8 } Complete struct { Binary string // 完整的16位二进制 RawValue uint16 // 原始值 Value float64 // 实际降雨量值 (计算公式: RawValue*0.254) } } // GetRainfall 解析降雨量数据 // RAIN_HH: bit 64-67 // RAIN_HL: bit 68-71 // RAIN_LH: bit 72-75 // RAIN_LL: bit 76-79 // 实际降雨量计算公式: value*0.254 func (p *Protocol) GetRainfall() (*Rainfall, error) { if len(p.RawData) < 10 { // 确保有足够的数据(bit 79 在第10个字节内) return nil, fmt.Errorf("insufficient data length") } result := &Rainfall{} // 解析 RAIN_HH 和 RAIN_HL (byte8) byte8 := p.RawData[8] rainHH := (byte8 >> 4) & 0x0F rainHL := byte8 & 0x0F result.RainHH.Binary = fmt.Sprintf("%04b", rainHH) result.RainHH.Value = rainHH result.RainHL.Binary = fmt.Sprintf("%04b", rainHL) result.RainHL.Value = rainHL // 解析 RAIN_LH 和 RAIN_LL (byte9) byte9 := p.RawData[9] rainLH := (byte9 >> 4) & 0x0F rainLL := byte9 & 0x0F result.RainLH.Binary = fmt.Sprintf("%04b", rainLH) result.RainLH.Value = rainLH result.RainLL.Binary = fmt.Sprintf("%04b", rainLL) result.RainLL.Value = rainLL // 组合完整的降雨量值 rawValue := (uint16(rainHH) << 12) | (uint16(rainHL) << 8) | (uint16(rainLH) << 4) | uint16(rainLL) result.Complete.Binary = fmt.Sprintf("%016b", rawValue) result.Complete.RawValue = rawValue // 计算实际降雨量值:value*0.254 result.Complete.Value = float64(rawValue) * 0.254 return result, nil } // UVIndex 存储紫外线指数数据 type UVIndex struct { UviHH struct { Binary string // bit 80-83 Value uint8 } UviHL struct { Binary string // bit 84-87 Value uint8 } UviLH struct { Binary string // bit 88-91 Value uint8 } UviLL struct { Binary string // bit 92-95 Value uint8 } Complete struct { Binary string // 完整的16位二进制 RawValue uint16 // 原始值 Value float64 // 实际紫外线值 (单位: uW/c㎡) IsValid bool // 是否有效 } } // GetUVIndex 解析紫外线指数数据 // UVI_HH: bit 80-83 // UVI_HL: bit 84-87 // UVI_LH: bit 88-91 // UVI_LL: bit 92-95 // Range: 0 uW/c㎡ to 20000 uW/c㎡ // If invalid fill with 0xFFFF func (p *Protocol) GetUVIndex() (*UVIndex, error) { if len(p.RawData) < 12 { // 确保有足够的数据(bit 95 在第12个字节内) return nil, fmt.Errorf("insufficient data length") } result := &UVIndex{} // 解析 UVI_HH 和 UVI_HL (byte10) byte10 := p.RawData[10] uviHH := (byte10 >> 4) & 0x0F uviHL := byte10 & 0x0F result.UviHH.Binary = fmt.Sprintf("%04b", uviHH) result.UviHH.Value = uviHH result.UviHL.Binary = fmt.Sprintf("%04b", uviHL) result.UviHL.Value = uviHL // 解析 UVI_LH 和 UVI_LL (byte11) byte11 := p.RawData[11] uviLH := (byte11 >> 4) & 0x0F uviLL := byte11 & 0x0F result.UviLH.Binary = fmt.Sprintf("%04b", uviLH) result.UviLH.Value = uviLH result.UviLL.Binary = fmt.Sprintf("%04b", uviLL) result.UviLL.Value = uviLL // 组合完整的紫外线值 rawValue := (uint16(uviHH) << 12) | (uint16(uviHL) << 8) | (uint16(uviLH) << 4) | uint16(uviLL) result.Complete.Binary = fmt.Sprintf("%016b", rawValue) result.Complete.RawValue = rawValue // 检查是否在有效范围内 (0-20000) if rawValue > 20000 { result.Complete.RawValue = 0xFFFF result.Complete.Value = 0 result.Complete.IsValid = false } else { result.Complete.Value = float64(rawValue) result.Complete.IsValid = true } return result, nil } // Light 存储光照数据 type Light struct { LightHH struct { Binary string // bit 96-99 Value uint8 } LightHL struct { Binary string // bit 100-103 Value uint8 } LightMH struct { Binary string // bit 104-107 Value uint8 } LightML struct { Binary string // bit 108-111 Value uint8 } LightLH struct { Binary string // bit 112-115 Value uint8 } LightLL struct { Binary string // bit 116-119 Value uint8 } Complete struct { Binary string // 完整的24位二进制 RawValue uint32 // 原始值 Value float64 // 实际光照值 (计算公式: RawValue/10) (单位: lux) IsValid bool // 是否有效 } } // GetLight 解析光照数据 // bit 96-119 (byte12-14: 00 04 9C) // 实际光照计算公式: value/10 // Range: 0.0 lux -> 300,000.0 lux // If invalid fill with 0xFFFFFF func (p *Protocol) GetLight() (*Light, error) { if len(p.RawData) < 15 { // 确保有足够的数据 return nil, fmt.Errorf("insufficient data length") } result := &Light{} // 获取三个字节 (00 04 9C) byte1 := p.RawData[12] // 00 byte2 := p.RawData[13] // 04 byte3 := p.RawData[14] // 9C // 组合完整的光照值 (00 04 9C) rawValue := (uint32(byte1) << 16) | (uint32(byte2) << 8) | uint32(byte3) result.Complete.Binary = fmt.Sprintf("%024b", rawValue) result.Complete.RawValue = rawValue // 检查是否在有效范围内 (0-3000000, 因为实际值要除以10) if rawValue > 3000000 { result.Complete.RawValue = 0xFFFFFF result.Complete.Value = 0 result.Complete.IsValid = false } else { result.Complete.Value = float64(rawValue) / 10.0 result.Complete.IsValid = true } return result, nil } // Pressure 存储大气压数据 type Pressure struct { PressureH struct { Binary string // bit 143-144 (补前导000) Value uint8 } PressureM struct { Binary string // bit 145-151 Value uint8 } PressureL struct { Binary string // bit 152-159 Value uint8 } Complete struct { Binary string // 完整的17位二进制 RawValue uint32 // 原始值 Value float64 // 实际气压值 (计算公式: RawValue/100) (单位: hPa) IsValid bool // 是否有效 } } // GetPressure 解析大气压数据 // 17位值组成:000 + bit143 + bit144-159 // 实际气压计算公式: value/100 // Range: 300.00 hPa -> 1200.00 hPa // If invalid fill with 0x1FFFF // Example: 0x018A9E = 1010.22 hPa func (p *Protocol) GetPressure() (*Pressure, error) { if len(p.RawData) < 20 { // 确保有足够的数据 return nil, fmt.Errorf("insufficient data length") } result := &Pressure{} // 获取三个字节 (01 88 F5) byte1 := p.RawData[17] // 01 byte2 := p.RawData[18] // 88 byte3 := p.RawData[19] // F5 // 组合完整的气压值 rawValue := (uint32(byte1) << 16) | (uint32(byte2) << 8) | uint32(byte3) result.Complete.Binary = fmt.Sprintf("%024b", rawValue) result.Complete.RawValue = rawValue // 检查是否在有效范围内 (30000-120000,因为实际值要除以100) if rawValue < 30000 || rawValue > 120000 { result.Complete.RawValue = 0x1FFFF result.Complete.Value = 0 result.Complete.IsValid = false } else { result.Complete.Value = float64(rawValue) / 100.0 result.Complete.IsValid = true } return result, nil } // RS485Protocol 定义RS485协议结构 type RS485Protocol struct { RawData []byte } // NewRS485Protocol 创建新的RS485协议实例 func NewRS485Protocol(data []byte) *RS485Protocol { return &RS485Protocol{ RawData: data, } } // ValidateRS485Data 验证RS485数据是否有效 func ValidateRS485Data(data []byte) bool { // 检查数据长度是否为25字节 if len(data) != 25 { return false } // 检查起始字节是否为0x24 if data[0] != 0x24 { return false } return true } // RS485WeatherData 存储RS485气象数据 type RS485WeatherData struct { Temperature float64 // 温度 Humidity float64 // 湿度 WindSpeed float64 // 风速 WindDirection float64 // 风向 Rainfall float64 // 雨量 Light float64 // 光照 UV float64 // 紫外线 Pressure float64 // 气压 DeviceID string // 设备ID ReceivedAt time.Time // 接收时间 RawDataHex string // 原始数据十六进制 } // ParseRS485Data 解析RS485数据 - 使用Protocol标准方法 func (p *RS485Protocol) ParseRS485Data() (*RS485WeatherData, error) { if !ValidateRS485Data(p.RawData) { return nil, fmt.Errorf("无效的RS485数据格式") } // 创建标准Protocol来解析数据 protocol := NewProtocol(p.RawData) data := &RS485WeatherData{} // 使用Protocol标准方法解析温度 if temp, err := protocol.GetTemperature(); err == nil { data.Temperature = temp.Complete.Value } // 使用Protocol标准方法解析湿度 if humidity, err := protocol.GetHumidity(); err == nil { data.Humidity = float64(humidity.Complete.Value) } // 使用Protocol标准方法解析风速 if windSpeed, err := protocol.GetWindSpeed(); err == nil { data.WindSpeed = windSpeed.Complete.Value } // 使用Protocol标准方法解析风向 if windDir, err := protocol.GetWindDirection(); err == nil { data.WindDirection = windDir.Complete.Degree } // 使用Protocol标准方法解析降雨量 if rainfall, err := protocol.GetRainfall(); err == nil { data.Rainfall = rainfall.Complete.Value } // 使用Protocol标准方法解析光照 if light, err := protocol.GetLight(); err == nil { data.Light = light.Complete.Value } // 使用Protocol标准方法解析UV指数 if uv, err := protocol.GetUVIndex(); err == nil { data.UV = uv.Complete.Value } // 使用Protocol标准方法解析气压 if pressure, err := protocol.GetPressure(); err == nil { data.Pressure = pressure.Complete.Value } return data, nil } // String 返回RS485WeatherData的字符串表示 func (w *RS485WeatherData) String() string { return fmt.Sprintf(` 设备ID: RS485-%s 温度: %.1f°C 湿度: %.1f%% 风向: %.1f° 风速: %.2f m/s 降雨量: %.2f mm 光照: %.2f lux 紫外线: %.2f 气压: %.2f hPa 时间: %s`, w.DeviceID, w.Temperature, w.Humidity, w.WindDirection, w.WindSpeed, w.Rainfall, w.Light, w.UV, w.Pressure, w.ReceivedAt.Format("2006-01-02 15:04:05"), ) }