// 一次操作循环 public override void Worker() { // 系统挂起的时候,不运行本线程 // 2007/12/18 //if (this.App.HangupReason == HangupReason.LogRecover) // return; if (this.App.ContainsHangup("LogRecover") == true) { return; } // 2012/2/4 if (this.App.PauseBatchTask == true) { return; } bool bFirst = true; string strError = ""; int nRet = 0; BatchTaskStartInfo startinfo = this.StartInfo; if (startinfo == null) { startinfo = new BatchTaskStartInfo(); // 按照缺省值来 } // 通用启动参数 bool bLoop = true; nRet = ParseMessageMonitorParam(startinfo.Param, out bLoop, out strError); if (nRet == -1) { this.AppendResultText("启动失败: " + strError + "\r\n"); return; } this.Loop = bLoop; string strID = ""; nRet = ParseMessageMonitorStart(startinfo.Start, out strID, out strError); if (nRet == -1) { this.AppendResultText("启动失败: " + strError + "\r\n"); this.Loop = false; return; } // bool bPerDayStart = false; // 是否为每日一次启动模式 string strMonitorName = "messageMonitor"; { string strLastTime = ""; nRet = ReadLastTime( strMonitorName, out strLastTime, out strError); if (nRet == -1) { string strErrorText = "从文件中获取 " + strMonitorName + " 每日启动时间时发生错误: " + strError; this.AppendResultText(strErrorText + "\r\n"); this.App.WriteErrorLog(strErrorText); return; } string strStartTimeDef = ""; // bRet 是否到了每日启动时间 bool bRet = false; string strOldLastTime = strLastTime; // return: // -2 strLastTime 格式错误 // -1 一般错误 // 0 没有找到startTime配置参数 // 1 找到了startTime配置参数 nRet = IsNowAfterPerDayStart( strMonitorName, ref strLastTime, out bRet, out strStartTimeDef, out strError); if (nRet == -1 || nRet == -2) { string strErrorText = "获取 " + strMonitorName + " 每日启动时间时发生错误: " + strError; this.AppendResultText(strErrorText + "\r\n"); this.App.WriteErrorLog(strErrorText); if (nRet == -2) { // 删除断点文件,避免下次继续报错 WriteLastTime(strMonitorName, ""); } return; } // 如果nRet == 0,表示没有配置相关参数,则兼容原来的习惯,每次都作 if (nRet == 0) { } else if (nRet == 1) { if (bRet == false) { if (this.ManualStart == true) { this.AppendResultText("已试探启动任务 '" + this.Name + "',但因没有到每日启动时间 " + strStartTimeDef + " 而未能启动。(上次任务处理结束时间为 " + DateTimeUtil.LocalTime(strLastTime) + ")\r\n"); } // 2014/3/31 if (string.IsNullOrEmpty(strOldLastTime) == true && string.IsNullOrEmpty(strLastTime) == false) { this.AppendResultText("史上首次启动此任务。已把当前时间当作上次任务处理结束时间 " + DateTimeUtil.LocalTime(strLastTime) + " 写入了断点记忆文件\r\n"); WriteLastTime(strMonitorName, strLastTime); } return; // 还没有到每日时间 } bPerDayStart = true; } this.App.WriteErrorLog((bPerDayStart == true ? "(定时)" : "(不定时)") + strMonitorName + " 启动。"); } AppendResultText("开始新一轮循环"); RmsChannel channel = this.RmsChannels.GetChannel(this.App.WsUrl); string strMessageDbName = this.App.MessageDbName; if (String.IsNullOrEmpty(strMessageDbName) == true) { AppendResultText("尚未配置消息库名(<message dbname='...' />)"); this.Loop = false; return; } if (String.IsNullOrEmpty(this.App.MessageReserveTimeSpan) == true) { AppendResultText("尚未配置消息保留期限(<message reserveTimeSpan='...' />"); this.Loop = false; return; } // 解析期限值 string strPeriodUnit = ""; long lPeriodValue = 0; nRet = LibraryApplication.ParsePeriodUnit( this.App.MessageReserveTimeSpan, out lPeriodValue, out strPeriodUnit, out strError); if (nRet == -1) { strError = "消息保留期限 值 '" + this.App.MessageReserveTimeSpan + "' 格式错误: " + strError; AppendResultText(strError); this.Loop = false; return; } AppendResultText("开始处理消息库 " + strMessageDbName + " 的循环"); // string strID = "1"; int nRecCount = 0; for (; ; nRecCount++) { // 系统挂起的时候,不运行本线程 // 2008/2/4 if (this.App.ContainsHangup("LogRecover") == true) { break; } // 2012/2/4 if (this.App.PauseBatchTask == true) { break; } if (this.Stopped == true) { break; } string strStyle = ""; strStyle = "data,content,timestamp,outputpath"; if (bFirst == true) { strStyle += ""; } else { strStyle += ",next"; } string strPath = strMessageDbName + "/" + strID; string strXmlBody = ""; string strMetaData = ""; string strOutputPath = ""; byte[] baOutputTimeStamp = null; // SetProgressText((nRecCount + 1).ToString() + " " + strPath); // 获得资源 // return: // -1 出错。具体出错原因在this.ErrorCode中。this.ErrorInfo中有出错信息。 // 0 成功 long lRet = channel.GetRes(strPath, strStyle, out strXmlBody, out strMetaData, out baOutputTimeStamp, out strOutputPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) { if (bFirst == true) { // 第一条没有找到, 但是要强制循环进行 bFirst = false; goto CONTINUE; } else { if (bFirst == true) { strError = "数据库 " + strMessageDbName + " 记录 " + strID + " 不存在。处理结束。"; } else { strError = "数据库 " + strMessageDbName + " 记录 " + strID + " 是最末一条记录。处理结束。"; } break; } } else if (channel.ErrorCode == ChannelErrorCode.EmptyRecord) { bFirst = false; // 把id解析出来 strID = ResPath.GetRecordId(strOutputPath); goto CONTINUE; } goto ERROR1; } bFirst = false; // 把id解析出来 strID = ResPath.GetRecordId(strOutputPath); try { // 处理 nRet = DoOneRecord( lPeriodValue, strPeriodUnit, strOutputPath, strXmlBody, baOutputTimeStamp, out strError); } catch (Exception ex) { strError = "DoOneRecord exception: " + ExceptionUtil.GetDebugText(ex); this.AppendResultText(strError + "\r\n"); this.SetProgressText(strError); nRet = -1; } if (nRet == -1) { AppendResultText("DoOneRecord() error : " + strError + "。\r\n"); } CONTINUE: continue; } // end of for // 正常结束,复位断点 this.App.RemoveBatchTaskBreakPointFile(this.Name); this.StartInfo.Start = ""; AppendResultText("针对消息库 " + strMessageDbName + " 的循环结束。共处理 " + nRecCount.ToString() + " 条记录。\r\n"); { Debug.Assert(this.App != null, ""); // 写入文件,记忆已经做过的当日时间 string strLastTime = DateTimeUtil.Rfc1123DateTimeStringEx(this.App.Clock.UtcNow.ToLocalTime()); // 2007/12/17 changed // DateTime.UtcNow // 2012/5/27 WriteLastTime(strMonitorName, strLastTime); string strErrorText = (bPerDayStart == true ? "(定时)" : "(不定时)") + strMonitorName + "结束。共处理记录 " + nRecCount.ToString() + " 个。"; this.App.WriteErrorLog(strErrorText); } return; ERROR1: // 记忆断点 this.StartInfo.Start = MemoBreakPoint( strID //strRecordID, ); this.Loop = true; // 便于稍后继续重新循环? startinfo.Param = MakeMessageMonitorParam( bLoop); AppendResultText("MessageMonitor thread error : " + strError + "\r\n"); this.App.WriteErrorLog("MessageMonitor thread error : " + strError + "\r\n"); return; }
// 针对读者记录中的 borrow 元素中 overflow (尚未超期)的,重新计算是否超额。如果不超额的,修改为正常的借期 // parameters: // now 当前时间。本地时间格式。这是用来判断是否超期的依据 // return.Value: // -1 出错 // 0 成功 // 1 有警告信息,在 strError 中返回 internal AdjustOverflowResult AdjustOverflow( XmlDocument readerdom, DateTime now, StringBuilder debugInfo) { List <ItemModifyInfo> modifies = new List <ItemModifyInfo>(); int nRet = BuildBorrowItemInfo(readerdom, now, out List <BorrowItemInfo> items, out string strError); if (nRet == -1) { return new AdjustOverflowResult { Value = -1, ErrorInfo = strError, Modifies = modifies } } ; // 没有任何在借事项 if (items.Count == 0) { return new AdjustOverflowResult { Value = 0, Modifies = modifies } } ; int overflow_count = BorrowItemInfo.CountOverflow(items); // 没有超额事项可供调整 if (overflow_count == 0) { return new AdjustOverflowResult { Value = 0, Modifies = modifies } } ; // 获得总的最大可借数 // return: // -1 出错 // 其他 最大可借册数 int totalMax = GetTotalMax( readerdom, out strError); if (totalMax == -1) { return new AdjustOverflowResult { Value = -1, ErrorInfo = strError, Modifies = modifies } } ; List <string> warnings = new List <string>(); var groups = BorrowItemInfo.GroupByBookType(items); // 对每种图书类型,尝试修正到本类型的最大许可外借数 foreach (var group in groups) { string bookType = group[0].BookType; // 获得特定图书类型的最大可借数 // return: // -1 出错 // 其他 此类型图书的最大可借册数 int typeMax = GetTypeMax( readerdom, bookType, out strError); if (typeMax == -1) { warnings.Add(strError); continue; // 放弃这一类型的处理,继续处理其他类型 } while (true) { // 统计数组中,正常借阅(非超额)的数量 int count = BorrowItemInfo.CountNormal(group); if (count < typeMax) { // 尝试从中改掉一个 overflow // return: // true 成功改掉一个 // false 没能改掉。(原因可能是因为没有可以改动状态的 overflow 元素了) var item = BorrowItemInfo.DecOverflow(group); if (item == null) { break; } // 检查总册数是否超额。如果超额,刚才的改动需要 undo int totalCount = BorrowItemInfo.CountNormal(items); if (totalCount > totalMax) { item.ModifyAction = null; // Undo break; } } else { break; } } } // 开始修改 borrow 元素 foreach (var item in items) { if (item.ModifyAction != "removeOverflow") { continue; } string strOldBorrowInfo = item.Element.OuterXml; // 获得一册书的借阅参数 nRet = GetBorrowParam( readerdom, item.BookType, item.BorrowDate, out string borrowPeriod, out string denyPeriod, out string returningDate, out strError); if (nRet == -1) { warnings.Add(strError); continue; } item.Element.SetAttribute("borrowPeriod", borrowPeriod); if (string.IsNullOrEmpty(denyPeriod) == false) { item.Element.SetAttribute("denyPeriod", denyPeriod); } else { item.Element.RemoveAttribute("denyPeriod"); } item.Element.SetAttribute("returningDate", returningDate); // 删除 overflow 属性 item.Element.RemoveAttribute("overflow"); modifies.Add(new ItemModifyInfo { LibraryCode = DomUtil.GetElementText(readerdom.DocumentElement, "libraryCode"), PatronBarcode = DomUtil.GetElementText(readerdom.DocumentElement, "barcode"), BorrowID = item.Element.GetAttribute("borrowID"), ItemBarcode = item.Barcode, BorrowDate = item.Element.GetAttribute("borrowDate"), BorrowPeriod = borrowPeriod, DenyPeriod = denyPeriod, ReturningDate = returningDate, OldBorrowInfo = strOldBorrowInfo, }); } /* * // 修改涉及到的册记录 * if (modifies.Count > 0 && sessioninfo != null) * { * foreach (var info in modifies) * { * nRet = ModifyItemRecord( * sessioninfo, * info, * out strError); * if (nRet == -1) * { * warnings.Add($"修改册记录 {info.ItemBarcode} 过程中出错: {strError}"); * debugInfo?.Append($"{warnings[warnings.Count - 1]}"); * } * } * } */ if (warnings.Count > 0) { strError = StringUtil.MakePathList(warnings, "; "); return(new AdjustOverflowResult { Value = 1, ErrorInfo = strError, Modifies = modifies }); } return(new AdjustOverflowResult { Value = 0, Modifies = modifies }); } #if NO // 针对读者记录中的 borrow 元素中 overflow (尚未超期)的,重新计算是否超额。如果不超额的,修改为正常的借期 // return: // -1 出错 // 0 成功 // 1 有警告信息,在 strError 中返回 int AdjustOverflow( SessionInfo sessioninfo, XmlDocument readerdom, StringBuilder debugInfo, out string strError) { strError = ""; int nRet = 0; debugInfo.AppendLine($"用于调整的读者记录: {DomUtil.GetIndentXml(readerdom)}"); List <string> warnings = new List <string>(); List <ItemModifyInfo> items = new List <ItemModifyInfo>(); string libraryCode = DomUtil.GetElementText(readerdom.DocumentElement, "libraryCode"); string readerType = DomUtil.GetElementText(readerdom.DocumentElement, "readerType"); // List<XmlElement> overflows = new List<XmlElement>(); debugInfo?.AppendLine($"libraryCode='{libraryCode}'"); debugInfo?.AppendLine($"readerType='{readerType}'"); var nodes = readerdom.DocumentElement.SelectNodes("borrows/borrow"); foreach (XmlElement borrow in nodes) { debugInfo?.AppendLine($"=== 对 borrow 元素进行处理: {borrow.OuterXml}"); if (borrow.HasAttribute("overflow") == false) { debugInfo?.AppendLine("没有 overflow 属性,跳过处理"); continue; } string no = borrow.GetAttribute("no"); if (string.IsNullOrEmpty(no) == false) { if (Int32.TryParse(no, out int value) == true) { if (value > 0) { debugInfo?.AppendLine("续借的情况跳过处理"); continue; // 续借的情况不考虑 } } else { warnings.Add($"续借次数 '{no}' 格式错误"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } } string itemBarcode = borrow.GetAttribute("barcode"); if (string.IsNullOrEmpty(itemBarcode)) { itemBarcode = "@refid:" + borrow.GetAttribute("refID"); } debugInfo?.AppendLine($"条码号='{itemBarcode}'"); try { // 获得借阅开始时间 string borrowDate = borrow.GetAttribute("borrowDate"); debugInfo?.AppendLine($"borrowDate='{borrowDate}'"); DateTime borrowTime = DateTimeUtil.FromRfc1123DateTimeString(borrowDate).ToLocalTime(); // 看看是否已经超期。已经超期的不处理 { string returningDate = borrow.GetAttribute("returningDate"); debugInfo?.AppendLine($"returningDate='{returningDate}'"); DateTime returningTime = DateTimeUtil.FromRfc1123DateTimeString(returningDate).ToLocalTime(); string period = borrow.GetAttribute("borrowPeriod"); debugInfo?.AppendLine($"borrowPeriod='{period}'"); nRet = LibraryApplication.ParsePeriodUnit(period, out long lPeriodValue, out string strPeriodUnit, out strError); if (nRet == -1) { debugInfo?.AppendLine($"ParsePeriodUnit('{period}') 出错:{strError}。只好把时间单位当作 day 来处理"); strPeriodUnit = "day"; // continue; } DateTime now = DateTime.Now; // 正规化时间 nRet = DateTimeUtil.RoundTime(strPeriodUnit, ref now, out strError); if (nRet == -1) { warnings.Add($"正规化时间出错(1)。strPeriodUnit={strPeriodUnit}"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } nRet = DateTimeUtil.RoundTime(strPeriodUnit, ref returningTime, out strError); if (nRet == -1) { warnings.Add($"正规化时间出错(2)。strPeriodUnit={strPeriodUnit}"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } if (returningTime < now) { debugInfo?.AppendLine($"已经超期,跳过处理 (returningTime={returningTime.ToString()}, now={now.ToString()})"); continue; } } string bookType = borrow.GetAttribute("type"); debugInfo?.AppendLine($"bookType='{bookType}'"); // 假设要首次借阅这一册,是否会超额? { // 从读者信息中,找出该读者以前已经借阅过的同类图书的册数 int nThisTypeCount = readerdom.DocumentElement.SelectNodes("borrows/borrow[@type='" + bookType + "']").Count; nRet = this.GetLoanParam( //null, libraryCode, readerType, bookType, "可借册数", out string strParamValue, out MatchResult _, out strError); if (nRet == -1) { warnings.Add($"获得 馆代码 '{ libraryCode }' 中 读者类型 '{ readerType }' 针对图书类型 '{ bookType }' 的 可借册数 参数时发生错误: {strError}"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } if (nRet < 4) { warnings.Add($"馆代码 '{ libraryCode}' 中 读者类型 '{ readerType }' 针对图书类型 '{ bookType }' 的 可借册数 参数无法获得: {strError}"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } if (Int32.TryParse(strParamValue, out int thisTypeMax) == false) { warnings.Add($"馆代码 '{ libraryCode}' 中 读者类型 '{ readerType }' 针对图书类型 '{ bookType }' 的 可借册数 参数 '{strParamValue}' 格式错误"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } // 依然超额了。不修改 if (nThisTypeCount > thisTypeMax) { debugInfo?.AppendLine($"特定类型的图书超额了,跳过处理。nThisTypeCount={nThisTypeCount}, thisTypeMax={thisTypeMax}, bookType={bookType}, readerType={readerType}"); continue; } // 看 可借总册数 nRet = this.GetLoanParam( //null, libraryCode, readerType, "", "可借总册数", out strParamValue, out MatchResult _, out strError); if (nRet == -1) { warnings.Add($"获得 馆代码 '{ libraryCode }' 中 读者类型 '{ readerType }' 的 可借总册数 参数时发生错误: {strError}"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } if (nRet < 3) { warnings.Add($"馆代码 '{ libraryCode}' 中 读者类型 '{ readerType }' 的 可借总册数 参数无法获得: {strError}"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } if (Int32.TryParse(strParamValue, out int max) == false) { warnings.Add($"馆代码 '{ libraryCode}' 中 读者类型 '{ readerType }' 的 可借总册数 参数 '{strParamValue}' 格式错误"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } // 从读者信息中,找出该读者已经借阅过的册数 int count = readerdom.DocumentElement.SelectNodes("borrows/borrow").Count; // 依然超额了。不修改 if (count > max) { debugInfo?.AppendLine($"全部图书超额了,跳过处理。count={count}, max={max}, readerType={readerType}"); continue; } } // return: // reader和book类型均匹配 算4分 // 只有reader类型匹配,算3分 // 只有book类型匹配,算2分 // reader和book类型都不匹配,算1分 nRet = this.GetLoanParam( libraryCode, readerType, bookType, "借期", out string strBorrowPeriodList, out MatchResult matchresult, out strError); if (nRet == -1) { warnings.Add($"获得 馆代码 '{ libraryCode }' 中 读者类型 '{ readerType }' 针对图书类型 '{ bookType }' 的 借期 参数时发生错误: {strError}"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } if (nRet < 4) // nRet == 0 { warnings.Add($"馆代码 '{ libraryCode}' 中 读者类型 '{ readerType }' 针对图书类型 '{ bookType }' 的 借期 参数无法获得: {strError}"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } string[] aPeriod = strBorrowPeriodList.Split(new char[] { ',' }); if (aPeriod.Length == 0) { warnings.Add($"'{strBorrowPeriodList}' Split error"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } string borrowPeriod = aPeriod[0]; if (string.IsNullOrEmpty(borrowPeriod)) { warnings.Add($"期限字符串 '{strBorrowPeriodList}' 中第一部分 '{borrowPeriod}' 为空"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } nRet = ParseBorrowPeriod(borrowPeriod, out string strThisBorrowPeriod, out string strThisDenyPeriod, out strError); if (nRet == -1) { warnings.Add($"ParseBorrowPeroid() '{borrowPeriod}' error"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } // 计算应还书时间 nRet = ComputeReturningDay( borrowTime, strThisBorrowPeriod, out DateTime this_return_time, out strError); if (nRet == -1) { warnings.Add($"ComputeReturningDay() error. borrowTime='{borrowTime}', strThisBorrowPeriod='{strThisBorrowPeriod}'"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); continue; } borrow.SetAttribute("borrowPeriod", strThisBorrowPeriod); // 2016/6/7 if (string.IsNullOrEmpty(strThisDenyPeriod) == false) { borrow.SetAttribute("denyPeriod", strThisDenyPeriod); } else { borrow.RemoveAttribute("denyPeriod"); } string strReturningDate = DateTimeUtil.Rfc1123DateTimeStringEx(this_return_time.ToLocalTime()); borrow.SetAttribute("returningDate", strReturningDate); // 删除 overflow 属性 borrow.RemoveAttribute("overflow"); items.Add(new ItemModifyInfo { ItemBarcode = itemBarcode, BorrowPeriod = strThisBorrowPeriod, DenyPeriod = strThisDenyPeriod, ReturningDate = strReturningDate }); } catch (Exception ex) { warnings.Add($"册记录 {itemBarcode} 处理过程出现异常: {ex.Message}"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); } } // 修改涉及到的册记录 if (items.Count > 0) { foreach (var info in items) { nRet = ModifyItemRecord( sessioninfo, info, out strError); if (nRet == -1) { warnings.Add($"修改册记录 {info.ItemBarcode} 过程中出错: {strError}"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); } } } if (warnings.Count > 0) { strError = StringUtil.MakePathList(warnings, "; "); return(1); } return(0); }
// 判断是否超过保留期限 // return: // -1 error // 0 没有超过 // 1 已经超过 int CheckeOutOfReservation( Calendar calendar, XmlDocument queue_rec_dom, out string strError) { strError = ""; string strState = DomUtil.GetElementText(queue_rec_dom.DocumentElement, "state"); // 对通知完成后的记录, 循环中不必处理 if (StringUtil.IsInList("outof", strState) == true) return 0; string strNotifyDate = DomUtil.GetElementText(queue_rec_dom.DocumentElement, "notifyDate"); /* string strItemBarcode = DomUtil.GetElementText(queue_rec_dom.DocumentElement, "itemBarcode"); string strReaderBarcode = DomUtil.GetElementText(queue_rec_dom.DocumentElement, "readerBarcode"); * */ // 解析期限值 string strPeriodUnit = ""; long lPeriodValue = 0; int nRet = LibraryApplication.ParsePeriodUnit( this.App.ArrivedReserveTimeSpan, out lPeriodValue, out strPeriodUnit, out strError); if (nRet == -1) { strError = "预约保留期限 值 '" + this.App.ArrivedReserveTimeSpan + "' 格式错误: " + strError; return -1; } // DateTime notifydate; try { notifydate = DateTimeUtil.FromRfc1123DateTimeString(strNotifyDate); } catch { strError = "通知日期值 '" + strNotifyDate + "' 格式错误"; return -1; } DateTime timeEnd = DateTime.MinValue; nRet = LibraryApplication.GetOverTime( calendar, notifydate, lPeriodValue, strPeriodUnit, out timeEnd, out strError); if (nRet == -1) { strError = "计算保留期过程发生错误: " + strError; return -1; } DateTime now = this.App.Clock.UtcNow; // DateTime.UtcNow; // 正规化时间 nRet = DateTimeUtil.RoundTime(strPeriodUnit, ref now, out strError); if (nRet == -1) return -1; TimeSpan delta = now - timeEnd; long lDelta = 0; nRet = LibraryApplication.ParseTimeSpan( delta, strPeriodUnit, out lDelta, out strError); if (nRet == -1) return -1; if (lDelta > 0) return 1; return 0; }
// parameters: // now 当前时间。本地时间格式。这是用来判断是否超期的依据 static bool IsOverdue(XmlElement borrow, DateTime now, out List <string> warnings) { warnings = new List <string>(); StringBuilder debugInfo = null; // 看看是否已经超期。已经超期的不处理 string returningDate = borrow.GetAttribute("returningDate"); // 2020/9/14 // 较旧的 dp2library 版本中没有 returningDate 属性,这种情况意味着所借图书的借阅时间很早很早了,可以简单当作已经超期来处理 // 注:也可以考虑这里尝试用 borrowDate 加上 borrowPeriod 来计算出应还时间,只是比较麻烦一点 if (string.IsNullOrEmpty(returningDate) == true) { return(true); } debugInfo?.AppendLine($"returningDate='{returningDate}'"); DateTime returningTime = DateTimeUtil.FromRfc1123DateTimeString(returningDate).ToLocalTime(); string period = borrow.GetAttribute("borrowPeriod"); debugInfo?.AppendLine($"borrowPeriod='{period}'"); int nRet = LibraryApplication.ParsePeriodUnit(period, out long lPeriodValue, out string strPeriodUnit, out string strError); if (nRet == -1) { debugInfo?.AppendLine($"ParsePeriodUnit('{period}') 出错:{strError}。只好把时间单位当作 day 来处理"); strPeriodUnit = "day"; // continue; } // DateTime now = DateTime.Now; // 正规化时间 nRet = DateTimeUtil.RoundTime(strPeriodUnit, ref now, out strError); if (nRet == -1) { warnings.Add($"正规化时间出错(1)。strPeriodUnit={strPeriodUnit}"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); return(false); } nRet = DateTimeUtil.RoundTime(strPeriodUnit, ref returningTime, out strError); if (nRet == -1) { warnings.Add($"正规化时间出错(2)。strPeriodUnit={strPeriodUnit}"); debugInfo?.Append($"{warnings[warnings.Count - 1]}"); return(false); } if (returningTime < now) { debugInfo?.AppendLine($"已经超期,跳过处理 (returningTime={returningTime.ToString()}, now={now.ToString()})"); return(true); } return(false); }