// 定时启动一个操作、任务
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers; /*
功能:定时启动一个操作。
作者:李茂平
用法:
this.TimeWork = new TimeWork(); this.TimeWork.AddWork(new TimeWorkItem()
{
任务名称 = "任务一",
Work = this.ClockMorningDownload,
计划启动时间 = "09:00",
任务说明 = "任务一说明 "
}); this.TimeWork.SetEnable(true); */
namespace ClassLibrary
{
/// <summary>
/// 定时执行任务的类,精度每分钟
/// </summary>
public class TimeWork : ObservableCollection<TimeWorkItem>
{
/// <summary>
/// 使用多线程计时器
/// </summary>
private readonly System.Timers.Timer timer1 = new System.Timers.Timer(); /// <summary>
/// 运行的分钟数
/// </summary>
private int CountMin { get; set; } = 0; /// <summary>
/// 当任务完成时
/// </summary>
public Action<TimeWorkItem, TimeWorkLogItem> OnWorkFinished { get; set; }
/// <summary>
/// 执行记录
/// </summary>
public ObservableCollection<TimeWorkLogItem> LogItems { get; set; } = new ObservableCollection<TimeWorkLogItem>();
/// <summary>
/// 构造函数,创建精度为1分钟的定时器
/// </summary>
public TimeWork()
{
this.timer1.Interval = 1 * 1000 * 60; // 1分钟的定时器
this.timer1.Elapsed += timerMinute_Elapsed;
this.timer1.Enabled = false; // 初始化为不发生定时事件
} /// <summary>
/// 是否启用定时任务
/// </summary>
/// <param name="bEnable"></param>
public void SetEnable(bool bEnable)
{
this.timer1.Enabled = bEnable;
ResetRunTime();
} /// <summary>
/// 定时器时间到,检查启动项目
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void timerMinute_Elapsed(object sender, ElapsedEventArgs e)
{
CountMin++; if (CountMin % 600 == 0) // 每10个小时重置一次
{
ResetRunTime();
} DoTimerWork();
} /// <summary>
/// 重新设定运行时间
/// </summary>
public void ResetRunTime()
{
foreach (var item in this)
{
item.InitRunTimes();
}
} /// <summary>
/// 定时器时间到,检查启动项目
/// </summary>
private void DoTimerWork()
{
DateTime now = DateTime.Now;
foreach (var item in this)
{
foreach (var time in item.RunTimes)
{
if (time.Hours == now.Hour &&
time.Minutes == now.Minute)
{
Thread t = new Thread(() =>
{
this.DoWork(item);
});
t.Start();
}
}
}
} /// <summary>
/// 添加一个定时执行的项目
/// </summary>
/// <param name="item"></param>
public void AddWork(TimeWorkItem item)
{
this.Add(item);
} /// <summary>
/// 执行任务
/// </summary>
/// <param name="item"></param>
public void DoWork(TimeWorkItem item)
{
if (item != null && item.Work != null)
{
DateTime begin = DateTime.Now;
item.Work(); // 执行工作 if (item.添加到执行记录)
LogItem(item, begin, DateTime.Now); item.上次执行时间 = begin.ToString("T");
}
} /// <summary>
/// 添加一条记录到文件,记录已经执行的任务
/// </summary>
/// <param name="item"></param>
private void LogItem(TimeWorkItem item, DateTime begin, DateTime end)
{
TimeWorkLogItem logItem = new TimeWorkLogItem(); logItem.任务名称 = item.任务名称;
logItem.执行时间 = begin;
logItem.完成时间 = end;
this.LogItems.Add(logItem); if (OnWorkFinished != null)
{
OnWorkFinished(item, logItem);
} //App.Data.UcDbModel.AddTimeWorksLog(logItem);
}
}
/// <summary>
/// MVVM模式下,更改属性的通知
/// 首先定义NotificationObject类。目的是绑定数据属性。
/// 这个类的作用是实现了INotifyPropertyChanged接口。
/// WPF中类要实现这个接口,其属性成员才具备通知UI的能力
/// </summary> public class NotificationObjectEF : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged; public void RaisePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
/// <summary>
/// 定时工作项目
/// </summary>
public class TimeWorkItem : NotificationObjectEF
{
public Action Work { get; set; }
public string 任务名称 { get; set; }
public string 任务说明 { get; set; }
/// <summary>
/// 设定的计划启动日期,空格分开,如:每周6,每月1,空白意味着每天
/// 空白 -- 启动
/// 周一 到 周日 启动
/// 5月2日 启动
/// </summary>
public string 计划启动日期 { get; set; }
/// <summary>
/// 空格分开的多个时间:15:00 16:32
/// </summary>
public string 计划启动时间 { get; set; }
/// <summary>
/// 间隔多少分钟重复,每天执行
/// </summary>
public int 间隔分钟 { get; set; }
/// <summary>
/// 是否记录到执行记录
/// </summary>
public bool 添加到执行记录 { get; set; } = true; private string 上次执行时间_; public string 上次执行时间
{
get
{
return 上次执行时间_;
}
set
{
上次执行时间_ = value;
RaisePropertyChanged("上次执行时间");
}
} /// <summary>
/// 运行任务的时间表
/// </summary>
public ObservableCollection<TimeSpan> RunTimes { get; set; } = new ObservableCollection<TimeSpan>(); /// <summary>
/// 运行任务的时间表
/// </summary>
private string runTimeStr; /// <summary>
/// 运行任务的时间表
/// </summary>
public string RunTimesStr
{
get
{
return runTimeStr;
}
set
{
runTimeStr = value;
RaisePropertyChanged("RunTimesStr");
}
} /// <summary>
/// 初始化时间
/// </summary>
public void InitRunTimes()
{
// 分析时间
RunTimes.Clear(); if (!string.IsNullOrEmpty(计划启动时间) && IsTodayRun())
{ string[] times = 计划启动时间.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
foreach (var item in times)
{
DateTime dt = new DateTime();
if (DateTime.TryParse(item, out dt))
{
RunTimes.Add(dt.TimeOfDay);
}
}
} if (间隔分钟 > 0 && string.IsNullOrEmpty(计划启动日期) && string.IsNullOrEmpty(计划启动时间))
{
DateTime now = DateTime.Now;
DateTime oneTime = now.AddMinutes(间隔分钟);
DateTime EndTime = now.AddHours(12); while (oneTime <= EndTime)
{
RunTimes.Add(oneTime.TimeOfDay);
oneTime = oneTime.AddMinutes(间隔分钟);
}
} // 设置字符串
string newRunTimesStr = "";
foreach (TimeSpan ts in RunTimes)
{
newRunTimesStr += $"{ts.Hours:00}:{ts.Minutes:00} ";
}
RunTimesStr = newRunTimesStr;
}
/// <summary>
/// 判断今日是否是执行日期.
/// 空白 -- 是
/// 周一 到周日 是
/// 5月2日 是
/// </summary>
/// <returns></returns>
private bool IsTodayRun()
{
if (string.IsNullOrEmpty(this.计划启动日期))
return true; string[] days = 计划启动日期.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
foreach (var item in days)
{
if (item.Contains("周") || item.Contains("星期"))
{
if (DateTime.Now.DayOfWeek == ConvertToDayOfWeek(item))
return true;
}
if (item.Contains("月") || item.Contains("日"))
{
string full = $"{DateTime.Now.Year}年" + item;
if(DateTime.TryParse(full, out DateTime setDate))
{
if (setDate.Date == DateTime.Now.Date)
return true;
} } }
return false;
} private DayOfWeek ConvertToDayOfWeek(string item)
{
switch(item)
{
case "周一":
case "星期一":
return DayOfWeek.Monday;
case "周二":
case "星期二":
return DayOfWeek.Tuesday;
case "周三":
case "星期三":
return DayOfWeek.Wednesday;
case "周四":
case "星期四":
return DayOfWeek.Thursday;
case "周五":
case "星期五":
return DayOfWeek.Monday;
case "周六":
case "星期六":
return DayOfWeek.Saturday;
case "周日":
case "星期日":
return DayOfWeek.Sunday;
default:
return DayOfWeek.Sunday; }
}
} [Serializable]
public class TimeWorkLogItem
{
/// <summary>
/// 名称
/// </summary>
public string 任务名称 { get; set; } /// <summary>
/// 上次执行时间
/// </summary>
public DateTime 执行时间 { get; set; } /// <summary>
/// 完成时间
/// </summary>
public DateTime 完成时间 { get; set; }
}
}

c# 定时启动一个操作、任务的更多相关文章

  1. C#定时执行一个操作

    一个客户端向服务器端socket发送报文,但是服务器端限制了发送频率,假如10秒内只能发送1次,这时客户端也要相应的做限制,初步的想法是在配置文件中保存上次最后发送的时间,当前发送时和这个上次最后时间 ...

  2. .Net Core 程序报错 在上一个操作完成之前,在此上下文上启动了第二个操作。

    错误一: 程序完整报错: A second operation started on this context before a previous operation completed. This ...

  3. 每天一个linux命令--定时启动

    1.设置启动的时间,输入crontab -e命令 设置一种编辑器,进入编辑界面,设置启动的时间为每5分钟启动一次wanghy.sh脚本 # m h dom mon dow command # */ * ...

  4. Winform定时启动

    System.Timers.Timer t; ; int qian; int bai; int shi; int ge; public 测试定时启动() { InitializeComponent() ...

  5. Spring-Kafka —— KafkaListener定时启动和停止

    一.定时启动的应用场景 比如现在单机环境下,我们需要利用Kafka做数据持久化的功能,由于用户活跃的时间为早上10点至晚上12点,那在这个时间段做一个大数据量的持久化可能会影响数据库性能导致用户体验降 ...

  6. SpringCloud升级之路2020.0.x版-20. 启动一个 Eureka Server 集群

    本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford 我们的业务集群结构 ...

  7. 【.net 深呼吸】启动一个进程并实时获取状态信息

    地球人和火星人都知道,Process类既可以获取正在运行的进程,也可以启动一个新的进程.在79.77%应用场合,我们只需要让目标进程顺利启动就完事了,至于它执行了啥,有没有出错,啥时候退出就不管了. ...

  8. C# 只启动一个实例完全解决方案

    工作上经常会遇到"程序只能启动一个实例"这样的需求. 我想,这样的需求应该很普遍,所以没打算去动脑筋,去找谷歌问下就得了,用下来发现,不是这里不爽就是那里不行. 先说下我详细的几点 ...

  9. Activiti系列:带有serviceTask的或者定时启动任务的流程部署失败的原因分析

    在将两个带有serviceTask任务的流程部署到数据库的时候发现无法导入,最终分析出如下问题: 1)流程1是打算让定时启动事件可以每小时触发一次 由于原来是用 R/2015-11-01T01:00: ...

随机推荐

  1. Spark在处理数据的时候,会将数据都加载到内存再做处理吗?

    对于Spark的初学者,往往会有一个疑问:Spark(如SparkRDD.SparkSQL)在处理数据的时候,会将数据都加载到内存再做处理吗? 很显然,答案是否定的! 对该问题产生疑问的根源还是对Sp ...

  2. winform导出csv

    public void ExportToSvc1(string strFileName) { string strPath = strFileName + ".csv"; Stri ...

  3. 微信小程序(七)-项目实例(原生框架 MINA转云开发)==02-云开发-配置

    云开发:1.就是用云函数的型式来使用云存储和云数据库完成各种操作!     2.只关注调什么函数,完成什么功能即可,无需关心HTTP请求哪一套!     3.此模式不代表没有服务器,只是部署在云环境中 ...

  4. Ajax的基本用法

    1.介绍 2.基本用法 2.1原生写法 $.ajax({ url: url, //是否是异步请求,默认是 // async: false, //请求方式,默认是get //type:'get', // ...

  5. 将VMware工作站最小化到托盘栏

    目录 前言 将VMware最小化到托盘栏的方法 1.下载 Trayconizer 2.解压 trayconizerw.zip 3.创建 VMware 快捷方式 4.修改 VMware 快捷方式 5.运 ...

  6. Prism -- 简介

    Prism是一个开源框架,用于在WPF.Xamarin Forms.Uno/Win UI等应用中创建松耦合.可维护.可测试的XAML应用程序.Prism提供了一组设计模式的实现,这些设计模式有助于编写 ...

  7. 后端程序员之路 45、nginx CORS 跨域

    在提供api给其它应用使用时,有时我们会要限制它的跨域使用,而有时,我们又要用CORS来打破AJAX只能同源使用的限制 跨域资源共享 CORS 详解 - 阮一峰的网络日志http://www.ruan ...

  8. 腾讯一面问我SQL语句中where条件为什么写上1=1

    目录 where后面加"1=1″还是不加 不用where 1=1 在多条件查询的困惑 使用where 1=1 的好处 使用where 1=1 的坏处 where后面加"1=1″还是 ...

  9. 测试平台系列(3) 给Hello World添加日志

    给Hello World添加日志 回顾 通过上篇内容,我们已经使用「Flask」完成了我们的第一个接口.我们可以看到,使用「Flask」来编写接口是十分简单的.那么接下来,我们丰富一下上面的例子. 需 ...

  10. 面试必备——Java多线程与并发(二)

    1.synchroized相关(锁的是对象,不是代码) (1)线程安全问题的主要原因 存在共享数据(也称临界资源) 存在多线程共同操作这些共享数据 解决:同一时刻有且只有一个线程在操作共享数据,其他线 ...