or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-features.mdcore-iteration.mdindex.mdrange-operations.mdvalidation-matching.md

validation-matching.mddocs/

0

# Validation and Matching

1

2

Comprehensive validation of cron expressions and testing whether specific datetime objects match cron patterns. This includes both single datetime matching and range-based matching capabilities.

3

4

## Capabilities

5

6

### Expression Validation

7

8

Validate cron expressions for syntax correctness and supported features.

9

10

```python { .api }

11

@classmethod

12

def is_valid(

13

cls,

14

expression: str,

15

hash_id=None,

16

encoding="UTF-8",

17

second_at_beginning=False,

18

) -> bool:

19

"""

20

Validate if a cron expression is syntactically correct and supported.

21

22

Parameters:

23

- expression: Cron expression string to validate

24

- hash_id: Hash ID for hashed expressions (bytes or str)

25

- encoding: Character encoding for hash_id if provided as string

26

- second_at_beginning: Whether seconds field is at beginning instead of end

27

28

Returns:

29

True if expression is valid, False otherwise

30

"""

31

```

32

33

### Single Datetime Matching

34

35

Test if a specific datetime matches a cron expression.

36

37

```python { .api }

38

@classmethod

39

def match(cls, cron_expression: str, testdate, day_or=True, second_at_beginning=False) -> bool:

40

"""

41

Test if a datetime matches the given cron expression.

42

43

Parameters:

44

- cron_expression: Cron expression string

45

- testdate: datetime object to test

46

- day_or: How to handle day and day_of_week fields (True=OR, False=AND)

47

- second_at_beginning: Whether seconds field is at beginning

48

49

Returns:

50

True if testdate matches the cron expression, False otherwise

51

"""

52

```

53

54

### Range-Based Matching

55

56

Test if a cron expression has any matches within a datetime range.

57

58

```python { .api }

59

@classmethod

60

def match_range(

61

cls,

62

cron_expression: str,

63

from_datetime,

64

to_datetime,

65

day_or=True,

66

second_at_beginning=False,

67

) -> bool:

68

"""

69

Test if a cron expression matches within a datetime range.

70

71

Parameters:

72

- cron_expression: Cron expression string

73

- from_datetime: Start of range (datetime object)

74

- to_datetime: End of range (datetime object)

75

- day_or: How to handle day and day_of_week fields (True=OR, False=AND)

76

- second_at_beginning: Whether seconds field is at beginning

77

78

Returns:

79

True if expression matches any time within the range, False otherwise

80

"""

81

```

82

83

## Usage Examples

84

85

### Basic Expression Validation

86

87

```python

88

from croniter import croniter

89

90

# Valid expressions

91

print(croniter.is_valid('0 0 1 * *')) # True - first day of month at midnight

92

print(croniter.is_valid('*/5 * * * *')) # True - every 5 minutes

93

print(croniter.is_valid('0 9-17 * * 1-5')) # True - business hours on weekdays

94

95

# Invalid expressions

96

print(croniter.is_valid('0 wrong_value 1 * *')) # False - invalid hour value

97

print(croniter.is_valid('60 * * * *')) # False - minute out of range

98

print(croniter.is_valid('* * 32 * *')) # False - day out of range

99

```

100

101

### Advanced Expression Validation

102

103

```python

104

from croniter import croniter

105

106

# Second-level precision (6-field format)

107

print(croniter.is_valid('30 */5 * * * *')) # True - every 5 minutes at 30 seconds

108

print(croniter.is_valid('*/15 * * * * *')) # True - every 15 seconds

109

110

# Year field (7-field format)

111

print(croniter.is_valid('0 0 1 1 * 0 2020/2')) # True - Jan 1st every 2 years from 2020

112

113

# Hashed expressions

114

print(croniter.is_valid('H H * * *', hash_id="job1")) # True - Jenkins-style hash

115

print(croniter.is_valid('H(0-30) H(9-17) * * *')) # True - hash with ranges

116

117

# Invalid advanced expressions

118

print(croniter.is_valid('0 0 1 1 * 0 2200')) # False - year out of range (>2099)

119

```

120

121

### Single Datetime Matching

122

123

```python

124

from croniter import croniter

125

from datetime import datetime

126

127

# Test specific datetime against cron expressions

128

test_dt = datetime(2019, 1, 14, 0, 0, 0) # January 14, 2019 at midnight

129

130

# Daily at midnight

131

print(croniter.match("0 0 * * *", test_dt)) # True - matches midnight

132

133

# Different time

134

test_dt2 = datetime(2019, 1, 14, 0, 2, 0) # 00:02

135

print(croniter.match("0 0 * * *", test_dt2)) # False - doesn't match midnight

136

137

# Weekday check

138

test_dt3 = datetime(2019, 1, 14, 9, 0, 0) # Monday morning

139

print(croniter.match("0 9 * * 1", test_dt3)) # True - 9 AM on Monday

140

141

# Complex expression with OR logic

142

test_dt4 = datetime(2019, 1, 1, 4, 2, 0) # January 1st at 04:02

143

print(croniter.match("2 4 1 * wed", test_dt4)) # True - 1st of month (OR logic)

144

```

145

146

### Day/Dayofweek Logic in Matching

147

148

```python

149

from croniter import croniter

150

from datetime import datetime

151

152

# January 1st, 2019 was a Tuesday

153

test_dt = datetime(2019, 1, 1, 4, 2, 0)

154

155

# OR logic (default): match if it's 1st of month OR if it's Wednesday

156

print(croniter.match("2 4 1 * wed", test_dt, day_or=True)) # True - it's 1st of month

157

158

# AND logic: match only if it's 1st of month AND it's Wednesday

159

print(croniter.match("2 4 1 * wed", test_dt, day_or=False)) # False - it's Tuesday, not Wednesday

160

161

# Test on a Wednesday that's not the 1st

162

wed_dt = datetime(2019, 1, 2, 4, 2, 0) # January 2nd, 2019 (Wednesday)

163

print(croniter.match("2 4 1 * wed", wed_dt, day_or=True)) # True - it's Wednesday (OR logic)

164

print(croniter.match("2 4 1 * wed", wed_dt, day_or=False)) # False - not 1st of month (AND logic)

165

```

166

167

### Range-Based Matching

168

169

```python

170

from croniter import croniter

171

from datetime import datetime

172

173

# Test if expression matches within a time range

174

start = datetime(2019, 1, 13, 0, 59, 0) # Before midnight

175

end = datetime(2019, 1, 14, 0, 1, 0) # After midnight

176

177

# Daily at midnight - should match within this range

178

print(croniter.match_range("0 0 * * *", start, end)) # True

179

180

# Different time range that doesn't include midnight

181

start2 = datetime(2019, 1, 13, 0, 1, 0)

182

end2 = datetime(2019, 1, 13, 0, 59, 0)

183

print(croniter.match_range("0 0 * * *", start2, end2)) # False

184

185

# Business hours check

186

start3 = datetime(2019, 1, 1, 3, 2, 0) # Before business hours

187

end3 = datetime(2019, 1, 1, 5, 1, 0) # Spans into business hours

188

print(croniter.match_range("2 4 1 * wed", start3, end3)) # True - 04:02 is in range

189

```

190

191

### Second-Level Precision Matching

192

193

```python

194

from croniter import croniter

195

from datetime import datetime

196

197

# Test with second-level precision

198

test_dt = datetime(2019, 1, 1, 0, 5, 30) # 30 seconds past 5 minutes

199

200

# Every 30 seconds (6-field format)

201

print(croniter.match("30 * * * * *", test_dt)) # True

202

203

# Different second

204

test_dt2 = datetime(2019, 1, 1, 0, 5, 15) # 15 seconds past 5 minutes

205

print(croniter.match("30 * * * * *", test_dt2)) # False

206

207

# Seconds at beginning format

208

print(croniter.match("30 5 0 1 1 *", test_dt, second_at_beginning=True)) # True

209

```

210

211

### Validation Error Handling

212

213

```python

214

from croniter import croniter

215

216

# Validation catches various error types

217

invalid_expressions = [

218

"invalid cron", # General syntax error

219

"* * * *", # Too few fields

220

"60 * * * *", # Minute out of range

221

"* 25 * * *", # Hour out of range

222

"* * 32 * *", # Day out of range

223

"* * * 13 *", # Month out of range

224

"* * * * 8", # Day of week out of range

225

"* * * jan13 *", # Invalid month name

226

]

227

228

for expr in invalid_expressions:

229

is_valid = croniter.is_valid(expr)

230

print(f"'{expr}': {is_valid}")

231

```

232

233

### Hash ID Validation

234

235

```python

236

from croniter import croniter

237

238

# Hashed expressions require hash_id for validation

239

print(croniter.is_valid("H H * * *")) # False - no hash_id

240

print(croniter.is_valid("H H * * *", hash_id="job1")) # True - with hash_id

241

242

# Hash ID can be string or bytes

243

print(croniter.is_valid("H H * * *", hash_id=b"job1")) # True - bytes hash_id

244

print(croniter.is_valid("H H * * *", hash_id="job1")) # True - string hash_id

245

246

# Custom encoding for string hash_id

247

print(croniter.is_valid("H H * * *", hash_id="jöb1", encoding="utf-8")) # True

248

```

249

250

### Practical Validation Scenarios

251

252

```python

253

from croniter import croniter

254

from datetime import datetime

255

256

def validate_cron_schedule(expression, test_datetime=None):

257

"""Validate a cron expression and optionally test against a datetime."""

258

259

# Basic validation

260

if not croniter.is_valid(expression):

261

return {"valid": False, "error": "Invalid cron expression syntax"}

262

263

# Test against specific datetime if provided

264

if test_datetime:

265

matches = croniter.match(expression, test_datetime)

266

return {

267

"valid": True,

268

"matches_test_time": matches,

269

"test_time": test_datetime

270

}

271

272

return {"valid": True}

273

274

# Example usage

275

result1 = validate_cron_schedule("0 9 * * 1-5") # Valid weekday morning expression

276

result2 = validate_cron_schedule("0 9 * * 1-5", datetime(2019, 1, 14, 9, 0)) # Monday 9 AM

277

result3 = validate_cron_schedule("invalid expression")

278

279

print(result1) # {'valid': True}

280

print(result2) # {'valid': True, 'matches_test_time': True, 'test_time': datetime(...)}

281

print(result3) # {'valid': False, 'error': 'Invalid cron expression syntax'}

282

```