【求助】关于工站24小时生产下跨天序列号生成
我有一个程序,主要功能是工站中采集每一个工件的数据记录到数据库,其中每个工件包含的信息包括但不限于入站时间、工件物料码、序列号等等;其中我的序列号计数规则以天来区分,比如:进入新的一天,序列号就从头开始计数,然后该工站24小时不间断生产;
但我最近遇到个奇怪的问题,在今天的23:29:54时间入站了一个工件,序列号是321,然后后续的工件在第二天0:41:53入站,可是后续的工件居然延续了昨天工件的序列号322,序列号没有重头开始计数,这显然不符合我的逻辑;
我的工件初始化是在入站的时候,序列号也在初始化的时候生成,请坛友帮我分析一下我关于生成序列号的函数,看看问题在哪里,代码如下:
public void SelectSerialNum()
{
var IntialTime = DateTime.Now.Date.ToString();
string Sql = $@"SELECT * FROM processTable WHERE CREATEDATE >= '{IntialTime}' ORDER BY SerialNumber ASC";
DataTable dt = DB.GetDataTable(Sql, BaseClass.conn);
if (dt.Rows.Count == 0)
{
this.SeralNum = "0001";
}
else
{
var maxSerialNumber = dt.AsEnumerable().Max(p => Convert.ToInt32(p.Field<string>("SerialNumber"))).ToString();
var nextSerialNumber = (Convert.ToInt32(maxSerialNumber) + 1).ToString("0000");
this.SeralNum = nextSerialNumber;
}
} 这个一般是你数据库时区设置不一致造成的,
如果MySQL数据库的话在数据库连接后面加上时区属性 &serverTimezone=Asia/Shanghai
判断当前时间是否已经过了一天(即大于当前日期的零点时间加一天),如果是,则将序列号重置为 "0001",否则按照原有逻辑生成下一个序列号。
public void SelectSerialNum()
{
var currentTime = DateTime.Now;
// 获取当前日期的零点时间
var initialTime = new DateTime(currentTime.Year, currentTime.Month, currentTime.Day);
string sql = $@"SELECT * FROM processTable WHERE CREATEDATE >= '{initialTime}' ORDER BY SerialNumber ASC";
DataTable dt = DB.GetDataTable(sql, BaseClass.conn);
if (dt.Rows.Count == 0)
{
this.SeralNum = "0001";
}
else
{
var maxSerialNumber = dt.AsEnumerable().Max(p => Convert.ToInt32(p.Field<string>("SerialNumber"))).ToString();
// 判断是否需要重置序列号
if (currentTime < initialTime.AddDays(1))
{
var nextSerialNumber = (Convert.ToInt32(maxSerialNumber) + 1).ToString("0000");
this.SeralNum = nextSerialNumber;
}
else
{
// 新的一天,序列号从头开始计数
this.SeralNum = "0001";
}
}
}
INSERT INTO test(y,m,d,id)SELECT YEAR(now())y,MONTH(NOW())m,DAY(now())d,(SELECT ifnull(MAX(id),0)+1 from test WHERE YEAR(now())=y,MONTH(NOW())=m,DAY(now())=d); CHATGPT的就不要回答了,我已经问过了,他给的答案都不靠谱 本帖最后由 luokack 于 2023-6-24 16:11 编辑
import datetime
def generate_serial_number(last_serial_number):
current_time = datetime.datetime.now()
today_start = current_time.replace(hour=0, minute=0, second=0, microsecond=0)
tomorrow_start = today_start + datetime.timedelta(days=1)
if current_time >= tomorrow_start:
return "0001"
else:
serial_number_int = int(last_serial_number)
serial_number_int += 1
return str(serial_number_int).zfill(4)
其中,last_serial_number 是上一个序列号,函数会根据它来生成下一个序列号。如果当前时间已经过了一天,则返回 "0001",否则将上一个序列号加一并返回。zfill(4) 是为了保证序列号的长度为 4,不足的部分用 0 填充。 看不出问题在哪里,但正常来说你代码不应该这样写。如果这张表只有一个进程在用,应该直接把当日的序号作为局部的静态变量缓存下来,并用关键字实现同步,写入数据库的时候把它转为字符串插入。至于每日重置也很简单,你记住上一次写入的时间,精确到日,然后比较这次和上次是否在同一日就行了,如果不是就更新日期,同时把变量清零;如果有多个进程,则应该利用触发器,让数据库在更新的时候自动帮你确定序号,把逻辑搬到触发器里 你的代码似乎在获取当天的工件序列号时遇到了问题。这是因为你在获取当天的日期并进行数据库查询时,使用了DateTime.Now.Date.ToString()。这个操作实际上会获取到当天的日期,并且时间会设置为00:00:00。
然后,你用这个日期时间去查询数据库中所有大于或等于这个日期时间的行。当你在凌晨0:41:53时运行此查询时,它会获取到昨天的23:29:54时间入站的工件,因为昨天的23:29:54是大于今天的00:00:00。所以,它会获取到昨天的工件,并继续昨天的序列号。
一个可能的解决方案是,明确指定查询日期的起始和结束时间,以确保只查询当天的工件。以下是修改后的代码:
public void SelectSerialNum()
{
var currentTime = DateTime.Now;
var initialTime = new DateTime(currentTime.Year, currentTime.Month, currentTime.Day, 0, 0, 0);
var endTime = initialTime.AddDays(1);
string Sql = $@"SELECT * FROM processTable WHERE CREATEDATE >= '{initialTime.ToString()}' AND CREATEDATE < '{endTime.ToString()}' ORDER BY SerialNumber ASC";
DataTable dt = DB.GetDataTable(Sql, BaseClass.conn);
if (dt.Rows.Count == 0)
{
this.SeralNum = "0001";
}
else
{
var maxSerialNumber = dt.AsEnumerable().Max(p => Convert.ToInt32(p.Field<string>("SerialNumber"))).ToString();
var nextSerialNumber = (Convert.ToInt32(maxSerialNumber) + 1).ToString("0000");
this.SeralNum = nextSerialNumber;
}
}
以上代码将查询时间限定为当天的0:00:00至次日的0:00:00,这样可以确保不会查询到昨天的工件。我在这里假设数据库中的CREATEDATE字段是一个时间戳或者日期时间字段,能够包含具体的时间信息。
来自chatGPT4的回答,看看对楼主有没有帮助 wkdxz 发表于 2023-6-24 15:44
判断当前时间是否已经过了一天(即大于当前日期的零点时间加一天),如果是,则将序列号重置为 "0001",否 ...
我觉得是可行的!{:1_921:} 侃遍天下无二人 发表于 2023-6-24 19:51
看不出问题在哪里,但正常来说你代码不应该这样写。如果这张表只有一个进程在用,应该直接把当日的序号作为 ...
谢谢,思路打开了!
页:
[1]
2