207 lines
6.3 KiB
Python
207 lines
6.3 KiB
Python
#!/usr/bin/env python3.9
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
JFinal TypeKit - Type Conversion Utilities
|
|
"""
|
|
|
|
from datetime import datetime, date, time, timedelta
|
|
from decimal import Decimal, InvalidOperation
|
|
import re
|
|
|
|
class TypeKit:
|
|
"""Type conversion utility class"""
|
|
|
|
_date_pattern = "yyyy-MM-dd"
|
|
_date_len = len(_date_pattern)
|
|
_date_time_without_second_pattern = "yyyy-MM-dd HH:mm"
|
|
_date_time_without_second_len = len(_date_time_without_second_pattern)
|
|
_date_time_pattern = "yyyy-MM-dd HH:mm:ss"
|
|
|
|
@staticmethod
|
|
def to_str(s) -> str:
|
|
"""Convert to string"""
|
|
return str(s) if s is not None else None
|
|
|
|
@staticmethod
|
|
def to_int(n) -> int:
|
|
"""Convert to integer"""
|
|
if n is None:
|
|
return None
|
|
if isinstance(n, int):
|
|
return n
|
|
if isinstance(n, float):
|
|
return int(n)
|
|
try:
|
|
return int(str(n))
|
|
except (ValueError, TypeError):
|
|
return None
|
|
|
|
@staticmethod
|
|
def to_long(n) -> int:
|
|
"""Convert to long integer"""
|
|
return TypeKit.to_int(n)
|
|
|
|
@staticmethod
|
|
def to_float(n) -> float:
|
|
"""Convert to float"""
|
|
if n is None:
|
|
return None
|
|
if isinstance(n, (int, float)):
|
|
return float(n)
|
|
try:
|
|
return float(str(n))
|
|
except (ValueError, TypeError):
|
|
return None
|
|
|
|
@staticmethod
|
|
def to_double(n) -> float:
|
|
"""Convert to double"""
|
|
return TypeKit.to_float(n)
|
|
|
|
@staticmethod
|
|
def to_decimal(n) -> Decimal:
|
|
"""Convert to Decimal"""
|
|
if n is None:
|
|
return None
|
|
if isinstance(n, Decimal):
|
|
return n
|
|
try:
|
|
return Decimal(str(n))
|
|
except (InvalidOperation, ValueError):
|
|
return None
|
|
|
|
@staticmethod
|
|
def to_big_decimal(n) -> Decimal:
|
|
"""Convert to BigDecimal"""
|
|
return TypeKit.to_decimal(n)
|
|
|
|
@staticmethod
|
|
def to_short(n) -> int:
|
|
"""Convert to short integer"""
|
|
result = TypeKit.to_int(n)
|
|
return result if result is None else max(-32768, min(32767, result))
|
|
|
|
@staticmethod
|
|
def to_byte(n) -> int:
|
|
"""Convert to byte integer"""
|
|
result = TypeKit.to_int(n)
|
|
return result if result is None else max(-128, min(127, result))
|
|
|
|
@staticmethod
|
|
def to_boolean(b) -> bool:
|
|
"""Convert to boolean"""
|
|
if b is None:
|
|
return None
|
|
if isinstance(b, bool):
|
|
return b
|
|
|
|
if isinstance(b, (int, float)):
|
|
if b == 1:
|
|
return True
|
|
elif b == 0:
|
|
return False
|
|
return bool(b)
|
|
|
|
if isinstance(b, str):
|
|
s = str(b).lower().strip()
|
|
if s in ("true", "1"):
|
|
return True
|
|
elif s in ("false", "0"):
|
|
return False
|
|
|
|
return bool(b)
|
|
|
|
@staticmethod
|
|
def to_number(n) -> float:
|
|
"""Convert to number"""
|
|
if n is None:
|
|
return None
|
|
if isinstance(n, (int, float)):
|
|
return float(n)
|
|
|
|
s = str(n)
|
|
if '.' in s:
|
|
return float(s)
|
|
else:
|
|
try:
|
|
return int(s)
|
|
except ValueError:
|
|
return float(s)
|
|
|
|
@staticmethod
|
|
def to_date(d):
|
|
"""Convert to datetime"""
|
|
if d is None:
|
|
return None
|
|
|
|
if isinstance(d, (datetime, date)):
|
|
if isinstance(d, datetime):
|
|
return d
|
|
else:
|
|
return datetime.combine(d, time.min)
|
|
|
|
if isinstance(d, str):
|
|
s = str(d).strip()
|
|
s_len = len(s)
|
|
|
|
if s_len <= TypeKit._date_len:
|
|
return TypeKit._parse_date(s, TypeKit._date_pattern)
|
|
elif s_len > TypeKit._date_time_without_second_len:
|
|
return TypeKit._parse_date(s, TypeKit._date_time_pattern)
|
|
else:
|
|
colon_count = s.count(':')
|
|
if colon_count == 2:
|
|
return TypeKit._parse_date(s, TypeKit._date_time_pattern)
|
|
elif colon_count == 1:
|
|
return TypeKit._parse_date(s, TypeKit._date_time_without_second_pattern)
|
|
|
|
raise ValueError(f"Cannot convert to date: {d}")
|
|
|
|
@staticmethod
|
|
def _parse_date(date_string: str, pattern: str) -> datetime:
|
|
"""Parse date string with pattern"""
|
|
try:
|
|
# Simplified date parsing - supports common formats
|
|
if pattern == "yyyy-MM-dd":
|
|
parts = date_string.split('-')
|
|
if len(parts) == 3:
|
|
return datetime(int(parts[0]), int(parts[1]), int(parts[2]))
|
|
elif pattern == "yyyy-MM-dd HH:mm:ss":
|
|
date_part, time_part = date_string.split(' ')
|
|
date_parts = date_part.split('-')
|
|
time_parts = time_part.split(':')
|
|
if len(date_parts) == 3 and len(time_parts) == 3:
|
|
return datetime(
|
|
int(date_parts[0]), int(date_parts[1]), int(date_parts[2]),
|
|
int(time_parts[0]), int(time_parts[1]), int(time_parts[2])
|
|
)
|
|
elif pattern == "yyyy-MM-dd HH:mm":
|
|
date_part, time_part = date_string.split(' ')
|
|
date_parts = date_part.split('-')
|
|
time_parts = time_part.split(':')
|
|
if len(date_parts) == 3 and len(time_parts) == 2:
|
|
return datetime(
|
|
int(date_parts[0]), int(date_parts[1]), int(date_parts[2]),
|
|
int(time_parts[0]), int(time_parts[1])
|
|
)
|
|
except (ValueError, IndexError):
|
|
pass
|
|
|
|
# Fallback to try parsing with dateutil or regex
|
|
raise ValueError(f"Cannot parse date: {date_string}")
|
|
|
|
@staticmethod
|
|
def to_local_date_time(ldt):
|
|
"""Convert to LocalDateTime"""
|
|
if ldt is None:
|
|
return None
|
|
|
|
if isinstance(ldt, datetime):
|
|
return ldt
|
|
|
|
d = TypeKit.to_date(ldt)
|
|
if d:
|
|
return d
|
|
|
|
raise ValueError(f"Cannot convert to LocalDateTime: {ldt}")
|