├── .gitignore ├── LICENSE ├── Package.swift ├── README.md ├── Sources └── SwiftLunar │ ├── BrassMonkeys.swift │ ├── Buddhis.swift │ ├── BuddhistFestival.swift │ ├── DogDays.swift │ ├── ExactDate.swift │ ├── Holiday.swift │ ├── JieQi.swift │ ├── Lunar.swift │ ├── LunarMonth.swift │ ├── LunarTime.swift │ ├── LunarYear.swift │ ├── NineStar.swift │ ├── Solar.swift │ ├── SolarHalfYear.swift │ ├── SolarMonth.swift │ ├── SolarSeason.swift │ ├── SolarWeek.swift │ ├── SolarYear.swift │ ├── Taoist.swift │ ├── TaoistFestival.swift │ ├── Timeset.swift │ ├── Timeset │ ├── DaYun.swift │ ├── LiuNian.swift │ ├── LiuYue.swift │ ├── XiaoYun.swift │ └── Yun.swift │ └── Utils │ ├── BuddhistUtil.swift │ ├── HolidayUtil.swift │ ├── LunarUtil.swift │ ├── ShouXingUtil.swift │ ├── SolarUtil.swift │ └── TaoistUtil.swift └── Tests └── SwiftLunarTests ├── BrassMonkeysTests.swift ├── BuddhisTests.swift ├── ConstellationTests.swift ├── CycleVoid.swift ├── DateTests.swift ├── DogDaysTests.swift ├── FestivalTests.swift ├── HalfYearTests.swift ├── HolidayTestst.swift ├── JulianDayTests.swift ├── LiuYaoTests.swift ├── LunarTests.swift ├── LunarYearTests.swift ├── MonthTests.swift ├── PhenologyTests.swift ├── SessonTests.swift ├── ShouXingUtilTests.swift ├── SolarTermsTests.swift ├── SolarTests.swift ├── SolarWeekTests.swift ├── TaoistTests.swift ├── TimeTests.swift ├── TimesetTests.swift ├── WeekTests.swift ├── YearTests.swift └── YunTests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 9 | *.xcscmblueprint 10 | *.xccheckout 11 | 12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 13 | build/ 14 | DerivedData/ 15 | *.moved-aside 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | 28 | ## App packaging 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | Packages/ 41 | # Package.pins 42 | # Package.resolved 43 | *.xcodeproj 44 | # 45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 46 | # hence it is not needed unless you have added a package configuration file to your project 47 | .swiftpm 48 | 49 | .build/ 50 | 51 | # CocoaPods 52 | # 53 | # We recommend against adding the Pods directory to your .gitignore. However 54 | # you should judge for yourself, the pros and cons are mentioned at: 55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 56 | # 57 | # Pods/ 58 | # 59 | # Add this line if you want to avoid checking in source code from the Xcode workspace 60 | # *.xcworkspace 61 | 62 | # Carthage 63 | # 64 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 65 | # Carthage/Checkouts 66 | 67 | Carthage/Build/ 68 | 69 | # Accio dependency management 70 | Dependencies/ 71 | .accio/ 72 | 73 | # fastlane 74 | # 75 | # It is recommended to not store the screenshots in the git repo. 76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 77 | # For more information about the recommended setup visit: 78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 79 | 80 | fastlane/report.xml 81 | fastlane/Preview.html 82 | fastlane/screenshots/**/*.png 83 | fastlane/test_output 84 | 85 | # Code Injection 86 | # 87 | # After new code Injection tools there's a generated folder /iOSInjectionProject 88 | # https://github.com/johnno1962/injectionforxcode 89 | 90 | iOSInjectionProject/ 91 | .DS_Store 92 | .netrc 93 | 94 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 6tail 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.6 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "SwiftLunar", 8 | products: [ 9 | // Products define the executables and libraries a package produces, and make them visible to other packages. 10 | .library( 11 | name: "SwiftLunar", 12 | targets: ["SwiftLunar"]), 13 | ], 14 | dependencies: [ 15 | // Dependencies declare other packages that this package depends on. 16 | // .package(url: /* package url */, from: "1.0.0"), 17 | ], 18 | targets: [ 19 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 20 | // Targets can depend on other targets in this package, and on products in packages this package depends on. 21 | .target( 22 | name: "SwiftLunar", 23 | dependencies: []), 24 | .testTarget( 25 | name: "SwiftLunarTests", 26 | dependencies: ["SwiftLunar"]), 27 | ] 28 | ) 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lunar [![License](https://img.shields.io/badge/license-MIT-4EB1BA.svg?style=flat-square)](https://github.com/bestheme/lunar-swift/blob/main/LICENSE) 2 | 3 | 4 | lunar是一款无第三方依赖的日历工具,支持公历(阳历)、农历(阴历、老黄历)、道历、佛历,支持星座、儒略日、干支、生肖、节气、节日、时间局、五行、法定节假日及调休等。 5 | 6 | 7 | 8 | ## 示例 9 | 10 | import SwiftLunar 11 | 12 | 13 | //今天 14 | //let date: Lunar = Lunar(fromDate: Date()); 15 | 16 | //指定阴历的某一天 17 | let date: Lunar = Lunar(fromYmd: 1986, month: 4, day: 21) 18 | print(date.toFullString()) 19 | print(date.getSolar().toFullString()) 20 | 21 | 22 | 输出结果: 23 | 24 | 一九八六年四月廿一 丙寅(虎)年 癸巳(蛇)月 癸酉(鸡)日 子(鼠)时 纳音[炉中火 长流水 剑锋金 桑柘木] 星期四 北方玄武 星宿[斗木獬](吉) 彭祖百忌[癸不词讼理弱敌强 酉不会客醉坐颠狂] 喜神方位[巽](东南) 阳贵神方位[巽](东南) 阴贵神方位[震](正东) 福神方位[兑](正西) 财神方位[离](正南) 冲[(丁卯)兔] 煞[东] 25 | 1986-05-29 00:00:00 星期四 双子座 26 | 27 | 28 | 感谢 [6tail](https://github.com/6tail) 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Sources/SwiftLunar/BrassMonkeys.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BrassMonkeys.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/22. 6 | // 7 | // 数九 8 | // Brass Monkeys 9 | 10 | public struct BrassMonkeys { 11 | /// 名称,如一九、二九 12 | public var name: String; 13 | 14 | /// 当前数九第几天,1-9 15 | public var index: Int = 1; 16 | 17 | public func toString() -> String{ 18 | return "\(name)" 19 | } 20 | 21 | public func toFullString() -> String { 22 | return "\(name)第\(index)天" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/SwiftLunar/Buddhis.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Buddhis.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/22. 6 | // 7 | // 佛历 8 | @available(watchOS 8.0, *) 9 | @available(iOS 15.0, *) 10 | @available(macOS 12.0, *) 11 | public struct Buddhis { 12 | static let DEAD_YEAR: Int = -543; 13 | 14 | /// 阴历 15 | public var lunarOfBuddhis: Lunar; 16 | 17 | public init(lunar: Lunar) { 18 | self.lunarOfBuddhis = lunar 19 | } 20 | 21 | public init(year: Int, month: Int, day: Int, hour: Int = 0, minute: Int = 0, second: Int = 0) { 22 | let y: Int = year + Buddhis.DEAD_YEAR - 1 23 | self.lunarOfBuddhis = Lunar(fromYmdHms: y, lunarMonth: month, lunarDay: day, hour: hour, minute: minute, second: second) 24 | } 25 | 26 | 27 | public var year: Int { 28 | get { 29 | let sy: Int = lunarOfBuddhis.getSolar().year; 30 | var y: Int = sy - Buddhis.DEAD_YEAR; 31 | if (sy == lunarOfBuddhis.year) { 32 | y += 1; 33 | } 34 | return y; 35 | } 36 | } 37 | 38 | public var month: Int { 39 | get { 40 | return lunarOfBuddhis.month 41 | } 42 | } 43 | 44 | public var day: Int { 45 | get { 46 | return lunarOfBuddhis.day 47 | } 48 | } 49 | 50 | public var yearInChinese: String { 51 | let y: String = "\(year)" 52 | var s: String = "" 53 | for v in y.utf16 { 54 | s += LunarUtil.NUMBER[Int(v) - 48] 55 | } 56 | return s; 57 | } 58 | 59 | public var monthInChinese: String { 60 | get { 61 | return lunarOfBuddhis.getMonthInChinese() 62 | } 63 | } 64 | 65 | public var dayInChinese: String { 66 | get { 67 | return lunarOfBuddhis.getDayInChinese() 68 | } 69 | } 70 | 71 | public var festivals: [BuddhistFestival] { 72 | var l: [BuddhistFestival] = []; 73 | let fs: [BuddhistFestival]? = BuddhistUtil.FESTIVAL["\(month)-\(day)"] 74 | if (nil != fs) { 75 | l.append(contentsOf: fs!) 76 | } 77 | return l; 78 | } 79 | 80 | public var isMonthZhai: Bool { 81 | get { 82 | let m: Int = month; 83 | return 1 == m || 5 == m || 9 == m; 84 | } 85 | } 86 | 87 | public var isDayYangGong: Bool { 88 | get { 89 | for festival in festivals { 90 | if ("杨公忌" == festival.name) { 91 | return true; 92 | } 93 | } 94 | return false 95 | } 96 | } 97 | 98 | public var isDayZhaiShuoWang: Bool { 99 | get { 100 | let d: Int = day 101 | return 1 == d || 15 == d 102 | } 103 | } 104 | 105 | public var isDayZhaiSix: Bool { 106 | get { 107 | let d: Int = day 108 | if (8 == d || 14 == d || 15 == d || 23 == d || 29 == d || 30 == d) { 109 | return true 110 | } else if (28 == d) { 111 | let m: LunarMonth? = LunarMonth.fromYm(lunarYear: lunarOfBuddhis.year, lunarMonth: month)! 112 | return nil != m && 30 != m!.dayCount 113 | } 114 | return false; 115 | } 116 | } 117 | 118 | public var isDayZhaiTen: Bool { 119 | get { 120 | let d: Int = day 121 | return 1 == d || 122 | 8 == d || 123 | 14 == d || 124 | 15 == d || 125 | 18 == d || 126 | 23 == d || 127 | 24 == d || 128 | 28 == d || 129 | 29 == d || 130 | 30 == d 131 | } 132 | } 133 | 134 | public var isDayZhaiGuanYin: Bool { 135 | get { 136 | let k: String = "\(month)-\(day)" 137 | for d in BuddhistUtil.DAY_ZHAI_GUAN_YIN { 138 | if (k == d) { 139 | return true; 140 | } 141 | } 142 | return false; 143 | } 144 | } 145 | 146 | var xiu: String { 147 | get { 148 | return BuddhistUtil.getXiu(month: month, day: day) 149 | } 150 | } 151 | 152 | var xiuLuck: String { 153 | get { 154 | return LunarUtil.XIU_LUCK[xiu]! 155 | } 156 | } 157 | 158 | var xiuSong: String { 159 | get { 160 | return LunarUtil.XIU_SONG[xiu]! 161 | } 162 | } 163 | 164 | var zheng: String { 165 | return LunarUtil.ZHENG[xiu]! 166 | } 167 | 168 | var animal: String { 169 | get { 170 | return LunarUtil.ANIMAL[xiu]! 171 | } 172 | } 173 | 174 | var gong: String { 175 | get { 176 | return LunarUtil.GONG[xiu]! 177 | } 178 | } 179 | 180 | var shou: String { 181 | get { 182 | return LunarUtil.SHOU[gong]! 183 | } 184 | } 185 | 186 | 187 | func toString() -> String { 188 | return "\(yearInChinese)年\(monthInChinese)月\(dayInChinese)" 189 | } 190 | 191 | func toFullString() -> String { 192 | var s: String = toString() 193 | for festival in festivals { 194 | s += " (" 195 | s += festival.toString() 196 | s += ")" 197 | } 198 | return s; 199 | } 200 | } 201 | 202 | -------------------------------------------------------------------------------- /Sources/SwiftLunar/BuddhistFestival.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BuddhistFestival.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/22. 6 | // 7 | // 佛历因果犯忌 8 | 9 | public struct BuddhistFestival { 10 | /// 是日何日,如:雷斋日 11 | public var name: String? 12 | 13 | /// 犯之因果,如:犯者夺纪 14 | public var result: String? 15 | 16 | /// 是否每月同 17 | public var everyMonth: Bool? 18 | 19 | /// 备注,如:宜先一日即戒 20 | public var remark: String? 21 | 22 | public init(name: String, result: String = "", everyMonth: Bool = false, remark: String = "") { 23 | self.name = name; 24 | self.result = result 25 | self.everyMonth = everyMonth 26 | self.remark = remark 27 | } 28 | 29 | public func isEveryMonth() -> Bool { 30 | return everyMonth! 31 | } 32 | 33 | func toString() -> String { 34 | return "\(name!)" 35 | } 36 | 37 | func toFullString() -> String { 38 | var s: String = "\(name!)" 39 | if (nil != result && result!.count > 0) { 40 | s += " "; 41 | s += result! 42 | } 43 | if (nil != remark && remark!.count > 0) { 44 | s += " " 45 | s += remark! 46 | } 47 | return s 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Sources/SwiftLunar/DogDays.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/21. 6 | // 7 | // Dog days 8 | //

从夏至后第3个庚日算起,初伏为10天,中伏为10天或20天,末伏为10天。当夏至与立秋之间出现4个庚日时中伏为10天,出现5个庚日则为20天。

9 | 10 | public struct DogDays { 11 | /// 名称:初伏、中伏、末伏 12 | public var name: String?; 13 | 14 | /// 当前入伏第几天,1-20 15 | public var index: Int = 1; 16 | 17 | public func toString() -> String{ 18 | return "\(name ?? "")" 19 | } 20 | 21 | public func toFullString() -> String { 22 | return "\(name ?? "")第\(index)天" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/SwiftLunar/ExactDate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExactDate.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/11. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 精确日期 11 | /// @author 6tail 12 | struct ExactDate { 13 | 14 | static func fromYmd(year: Int, month: Int, day: Int) -> Date { 15 | return fromYmdHms(year: year, month: month, day: day, hour: 0, minute: 0, second: 0); 16 | } 17 | 18 | static func fromYmdHms(year: Int, month: Int, day: Int, hour: Int, minute: Int, second: Int) -> Date { 19 | let dc = DateComponents(calendar: Calendar(identifier: .gregorian), year: year, month: month, day: day, hour: hour, minute: minute, second: second) 20 | return dc.date! 21 | } 22 | 23 | static func fromDate(date: Date) -> Date { 24 | let dc = Calendar(identifier: .gregorian).dateComponents([.year, .month, .day, .hour, .minute, .second], from: date) 25 | return fromYmdHms(year: 26 | dc.year!, month: dc.month!, day: dc.day!, hour: dc.hour!, minute: dc.minute!, second: dc.second!) 27 | } 28 | 29 | /// 获取两个日期之间相差的天数(如果日期a比日期b小,天数为正,如果日期a比日期b大,天数为负) 30 | /// 31 | /// @param ay 年a 32 | /// @param am 月a 33 | /// @param ad 日a 34 | /// @param by 年b 35 | /// @param bm 月b 36 | /// @param bd 日b 37 | /// @return 天数 38 | static func getDaysBetween(ay: Int, am: Int, ad: Int, by: Int, bm: Int, bd: Int) -> Int { 39 | let calendar = Calendar.current 40 | let startDate = fromYmd(year: ay, month: am, day: ad) 41 | let endDate = fromYmd(year: by, month: bm, day: bd) 42 | let diff: DateComponents = calendar.dateComponents([.day], from: startDate, to: endDate) 43 | return diff.day! 44 | } 45 | 46 | /// 获取两个日期之间相差的天数(如果日期a比日期b小,天数为正,如果日期a比日期b大,天数为负) 47 | /// 48 | /// @param calendar0 日期a 49 | /// @param calendar1 日期b 50 | /// @return 天数 51 | static func getDaysBetweenDate(startDate: Date, endDate: Date) -> Int { 52 | let calendar = Calendar.current 53 | let diff: DateComponents = calendar.dateComponents([.day], from: startDate, to: endDate) 54 | return diff.day! 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Sources/SwiftLunar/Holiday.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Holiday.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/12. 6 | // 7 | 8 | import Foundation 9 | 10 | //节假日 11 | 12 | struct Holiday { 13 | // 日期,YYYY/MM/DD格式 14 | var day: String? 15 | 16 | // 名称,如:国庆 17 | var name: String? 18 | 19 | // 是否调休,即是否要上班 20 | var isWork: Bool = false 21 | 22 | // 关联的节日,YYYY/MM/DD格式 23 | var target: String? 24 | 25 | init(day: String, name: String, work: Bool, target: String) { 26 | // if (!day.contains('-')) { 27 | // day = day.substring(0, 4) + 28 | // '-' + 29 | // day.substring(4, 6) + 30 | // '-' + 31 | // day.substring(6); 32 | // } else { 33 | self.day = day 34 | // } 35 | self.name = name 36 | self.isWork = work 37 | // if (!target.contains('-')) { 38 | // _target = target.substring(0, 4) + 39 | // '-' + 40 | // target.substring(4, 6) + 41 | // '-' + 42 | // target.substring(6); 43 | // } else { 44 | self.target = target 45 | // } 46 | } 47 | 48 | // String getDay() => _day!; 49 | 50 | // void setDay(String day) { 51 | // _day = day; 52 | // } 53 | 54 | // String getName() => _name!; 55 | // 56 | // void setName(String name) { 57 | // _name = name; 58 | // } 59 | 60 | // bool isWork() => _work; 61 | // 62 | // void setWork(bool work) { 63 | // _work = work; 64 | // } 65 | 66 | // String getTarget() => _target!; 67 | // 68 | // void setTarget(String target) { 69 | // _target = target; 70 | // } 71 | 72 | 73 | func toString() -> String { 74 | return "\(String(describing: day)) \(String(describing: name))\((isWork) ? "调休" : "") \(String(describing: target))" 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Sources/SwiftLunar/JieQi.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JieQI.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/19. 6 | // 7 | // Solar terms 8 | @available(watchOS 8.0, *) 9 | @available(iOS 15.0, *) 10 | @available(macOS 12.0, *) 11 | public struct JieQi { 12 | static let JIE_QI: [String] = [ 13 | "冬至", 14 | "小寒", 15 | "大寒", 16 | "立春", 17 | "雨水", 18 | "惊蛰", 19 | "春分", 20 | "清明", 21 | "谷雨", 22 | "立夏", 23 | "小满", 24 | "芒种", 25 | "夏至", 26 | "小暑", 27 | "大暑", 28 | "立秋", 29 | "处暑", 30 | "白露", 31 | "秋分", 32 | "寒露", 33 | "霜降", 34 | "立冬", 35 | "小雪", 36 | "大雪" 37 | ]; 38 | 39 | /// 名称 40 | public var name: String? { 41 | didSet { 42 | for i in 0.. _name!; 69 | 70 | // void setName(String name) { 71 | // _name = name; 72 | // for (int i = 0, j = JIE_QI.length; i < j; i++) { 73 | // if (name == JIE_QI[i]) { 74 | // if (i % 2 == 0) { 75 | // _qi = true; 76 | // } else { 77 | // _jie = true; 78 | // } 79 | // return; 80 | // } 81 | // } 82 | // } 83 | 84 | // Solar getSolar() => _solar!; 85 | 86 | // void setSolar(Solar solar) { 87 | // _solar = solar; 88 | // } 89 | 90 | // bool isJie() => _jie; 91 | // 92 | // bool isQi() => _qi; 93 | 94 | public func toString() -> String { 95 | return String(describing: name) 96 | } 97 | } 98 | 99 | -------------------------------------------------------------------------------- /Sources/SwiftLunar/LunarMonth.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LunarMonth.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/12. 6 | // 7 | 8 | import Foundation 9 | 10 | // 农历月 11 | @available(watchOS 8.0, *) 12 | @available(iOS 15.0, *) 13 | @available(macOS 12.0, *) 14 | public struct LunarMonth { 15 | /// 农历年 16 | public var year: Int = 0 17 | 18 | /// 农历月:1-12,闰月为负数,如闰2月为-2 19 | public var month: Int = 0 20 | 21 | /// 天数,大月30天,小月29天 22 | public var dayCount: Int = 0 23 | 24 | /// 初一的儒略日 25 | public var firstJulianDay: Double = 0 26 | 27 | public init(year: Int, month: Int, dayCount: Int, firstJulianDay: Double) { 28 | self.year = year 29 | self.month = month 30 | self.dayCount = dayCount 31 | self.firstJulianDay = firstJulianDay 32 | } 33 | 34 | 35 | static func fromYm(lunarYear: Int, lunarMonth: Int) -> LunarMonth? { 36 | return LunarYear.fromYear(lunarYear: lunarYear).getMonth(lunarMonth: lunarMonth) 37 | } 38 | 39 | public func getYear() -> Int { 40 | return year 41 | } 42 | 43 | public func getMonth() -> Int { 44 | return month 45 | } 46 | 47 | public func getDayCount() -> Int { 48 | return dayCount 49 | } 50 | 51 | public func getFirstJulianDay() -> Double { 52 | return firstJulianDay 53 | } 54 | 55 | public func isLeap() -> Bool { 56 | return month < 0 57 | } 58 | 59 | func getPositionTaiSui() -> String { 60 | var p: String = "" 61 | let m: Int = abs(month) 62 | switch (m) { 63 | case 1: break 64 | case 5: break 65 | case 9: 66 | p = "艮" 67 | break 68 | case 3: break 69 | case 7: break 70 | case 11: 71 | p = "坤" 72 | break 73 | case 4: break 74 | case 8: break 75 | case 12: 76 | p = "巽" 77 | break 78 | default: 79 | p = LunarUtil.POSITION_GAN[Solar(fromJulianDay: self.getFirstJulianDay()) 80 | .getLunar() 81 | .getMonthGanIndex()] 82 | } 83 | return p 84 | } 85 | 86 | func getPositionTaiSuiDesc() -> String { 87 | return LunarUtil.POSITION_DESC[getPositionTaiSui()]! 88 | } 89 | 90 | // func getNineStar() -> NineStar { 91 | // var index: Int = LunarYear(lunarYear: year).getZhiIndex() % 3 92 | // var m: Int = abs(month) 93 | // var monthZhiIndex: Int = (13 + m) % 12 94 | // var n: Int = 27 - (index * 3) 95 | // if (monthZhiIndex < LunarUtil.BASE_MONTH_ZHI_INDEX) { 96 | // n -= 3 97 | // } 98 | // var offset: Int = (n - monthZhiIndex) % 9 99 | // return NineStar.fromIndex(offset) 100 | // } 101 | 102 | func toString() -> String { 103 | let month: String = LunarUtil.MONTH[abs(month)] 104 | return "\(year)年\(isLeap() ? "闰" : "")\(month)月(\(dayCount))天" 105 | } 106 | 107 | func next(n: Int) -> LunarMonth{ 108 | if (0 == n) { 109 | return LunarMonth.fromYm(lunarYear: year, lunarMonth: month)! 110 | } else if (n > 0) { 111 | var rest: Int = n 112 | var ny: Int = year 113 | var iy: Int = ny 114 | var im: Int = month 115 | var index: Int = 0 116 | var months: [LunarMonth] = LunarYear(lunarYear: ny).getMonths() 117 | while (true) { 118 | let size: Int = months.count 119 | for i in 0.. Int { 32 | return ganIndex 33 | } 34 | 35 | public func getZhiIndex() -> Int { 36 | return zhiIndex 37 | } 38 | 39 | public func getShengXiao() -> String { 40 | return LunarUtil.SHENGXIAO[zhiIndex + 1] 41 | } 42 | 43 | public func getGan() -> String { 44 | return LunarUtil.GAN[ganIndex + 1] 45 | } 46 | 47 | public func getZhi() -> String { 48 | return LunarUtil.ZHI[zhiIndex + 1] 49 | } 50 | 51 | public func getGanZhi() -> String { 52 | return "\(getGan())\(getZhi())" 53 | } 54 | 55 | func getPositionXi() -> String { 56 | return LunarUtil.POSITION_XI[ganIndex + 1] 57 | } 58 | 59 | func getPositionXiDesc() -> String { 60 | return LunarUtil.POSITION_DESC[getPositionXi()]! 61 | } 62 | 63 | func getPositionYangGui() -> String { 64 | return LunarUtil.POSITION_YANG_GUI[ganIndex + 1] 65 | } 66 | 67 | func getPositionYangGuiDesc() -> String { 68 | return LunarUtil.POSITION_DESC[getPositionYangGui()]! 69 | } 70 | 71 | func getPositionYinGui() -> String { 72 | return LunarUtil.POSITION_YIN_GUI[ganIndex + 1] 73 | } 74 | 75 | func getPositionYinGuiDesc() -> String { 76 | return LunarUtil.POSITION_DESC[getPositionYinGui()]! 77 | } 78 | 79 | func getPositionFu(geren: Int = 1) -> String { 80 | return (1 == geren 81 | ? LunarUtil.POSITION_FU 82 | : LunarUtil.POSITION_FU_2)[ganIndex + 1] 83 | } 84 | 85 | func getPositionFuDesc(geren: Int = 1 ) -> String { 86 | return LunarUtil.POSITION_DESC[getPositionFu(geren: geren)]! 87 | } 88 | 89 | func getPositionCai() -> String { 90 | return LunarUtil.POSITION_CAI[ganIndex + 1] 91 | } 92 | 93 | func getPositionCaiDesc() -> String { 94 | return LunarUtil.POSITION_DESC[getPositionCai()]! 95 | } 96 | 97 | func getNaYin() -> String { 98 | return LunarUtil.NAYIN[getGanZhi()]! 99 | } 100 | 101 | func getTianShen() -> String { 102 | let dayZhi: String = lunar!.getDayZhiExact() 103 | let offset: Int = LunarUtil.ZHI_TIAN_SHEN_OFFSET[dayZhi]! 104 | return LunarUtil.TIAN_SHEN[(zhiIndex + offset) % 12 + 1] 105 | } 106 | 107 | func getTianShenType() -> String { 108 | return LunarUtil.TIAN_SHEN_TYPE[getTianShen()]! 109 | } 110 | 111 | func getTianShenLuck() -> String { 112 | return LunarUtil.TIAN_SHEN_TYPE_LUCK[getTianShenType()]! 113 | } 114 | 115 | public func getChong() -> String { 116 | return LunarUtil.CHONG[zhiIndex] 117 | } 118 | 119 | func getSha() -> String { 120 | return LunarUtil.SHA[getZhi()]! 121 | } 122 | 123 | func getChongShengXiao() -> String { 124 | let chong: String = getChong() 125 | for i in 0.. String { 134 | "(\(getChongGan())\(getChong()))\(getChongShengXiao())" 135 | } 136 | 137 | public func getChongGan() -> String { 138 | return LunarUtil.CHONG_GAN[ganIndex] 139 | } 140 | 141 | func getChongGanTie() -> String { 142 | return LunarUtil.CHONG_GAN_TIE[ganIndex] 143 | } 144 | 145 | func getYi() -> [String] { 146 | return LunarUtil.getTimeYi(dayGanZhi: lunar!.getDayInGanZhiExact(), timeGanZhi: getGanZhi()) 147 | } 148 | 149 | func getJi() -> [String] { 150 | return LunarUtil.getTimeJi(dayGanZhi: lunar!.getDayInGanZhiExact(), timeGanZhi: getGanZhi()) 151 | } 152 | 153 | // func getNineStar() -> NineStar { 154 | // //顺逆 155 | // String solarYmd = _lunar!.getSolar().toYmd() 156 | // Map jieQi = _lunar!.getJieQiTable() 157 | // bool asc = false 158 | // if (solarYmd.compareTo(jieQi["冬至"]!.toYmd()) >= 0 && 159 | // solarYmd.compareTo(jieQi["夏至"]!.toYmd()) < 0) { 160 | // asc = true 161 | // } 162 | // int start = asc ? 7 : 3 163 | // String dayZhi = _lunar!.getDayZhi() 164 | // if ("子午卯酉".contains(dayZhi)) { 165 | // start = asc ? 1 : 9 166 | // } else if ("辰戌丑未".contains(dayZhi)) { 167 | // start = asc ? 4 : 6 168 | // } 169 | // int index = asc ? start + _zhiIndex - 1 : start - _zhiIndex - 1 170 | // if (index > 8) { 171 | // index -= 9 172 | // } 173 | // if (index < 0) { 174 | // index += 9 175 | // } 176 | // return NineStar(index) 177 | // } 178 | 179 | 180 | func toString() -> String { 181 | return getGanZhi() 182 | } 183 | 184 | public func getXun() -> String { 185 | return LunarUtil.getXun(ganZhi: getGanZhi()) 186 | } 187 | 188 | public func getXunKong() -> String { 189 | return LunarUtil.getXunKong(ganZhi: getGanZhi()) 190 | } 191 | 192 | func getMinHm() -> String { 193 | var hour: Int = lunar!.hour 194 | if (hour < 1) { 195 | return "00:00" 196 | } else if (hour > 22) { 197 | return "23:00" 198 | } 199 | if (hour % 2 == 0) { 200 | hour -= 1 201 | } 202 | return "\(hour < 10 ? "0" : "")\(hour):00" 203 | } 204 | 205 | func getMaxHm() -> String { 206 | var hour: Int = lunar!.hour 207 | if (hour < 1) { 208 | return "00:59" 209 | } else if (hour > 22) { 210 | return "23:59" 211 | } 212 | if (hour % 2 != 0) { 213 | hour += 1 214 | } 215 | return "\(hour < 10 ? "0" : "")\(hour):59" 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /Sources/SwiftLunar/NineStar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NineStar.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/21. 6 | // 7 | // 九星 8 | //

玄空九星、奇门九星都来源于北斗九星,九数、七色、五行、后天八卦方位都是相通的。

9 | // 10 | struct NineStar { 11 | /// 九数 12 | static let NUMBER: [String] = [ 13 | "一", 14 | "二", 15 | "三", 16 | "四", 17 | "五", 18 | "六", 19 | "七", 20 | "八", 21 | "九" 22 | ]; 23 | 24 | /// 七色 25 | static let COLOR: [String] = [ 26 | "白", 27 | "黒", 28 | "碧", 29 | "绿", 30 | "黄", 31 | "白", 32 | "赤", 33 | "白", 34 | "紫" 35 | ]; 36 | 37 | /// 五行 38 | static let WU_XING: [String] = [ 39 | "水", 40 | "土", 41 | "木", 42 | "木", 43 | "土", 44 | "金", 45 | "金", 46 | "土", 47 | "火" 48 | ]; 49 | 50 | /// 后天八卦方位 51 | static let POSITION: [String] = [ 52 | "坎", 53 | "坤", 54 | "震", 55 | "巽", 56 | "中", 57 | "乾", 58 | "兑", 59 | "艮", 60 | "离" 61 | ]; 62 | 63 | /// 北斗九星 64 | static let NAME_BEI_DOU: [String] = [ 65 | "天枢", 66 | "天璇", 67 | "天玑", 68 | "天权", 69 | "玉衡", 70 | "开阳", 71 | "摇光", 72 | "洞明", 73 | "隐元" 74 | ]; 75 | 76 | /// 玄空九星(玄空风水) 77 | static let NAME_XUAN_KONG: [String] = [ 78 | "贪狼", 79 | "巨门", 80 | "禄存", 81 | "文曲", 82 | "廉贞", 83 | "武曲", 84 | "破军", 85 | "左辅", 86 | "右弼" 87 | ]; 88 | 89 | /// 奇门九星(奇门遁甲,也称天盘九星) 90 | static let NAME_QI_MEN: [String] = [ 91 | "天蓬", 92 | "天芮", 93 | "天冲", 94 | "天辅", 95 | "天禽", 96 | "天心", 97 | "天柱", 98 | "天任", 99 | "天英" 100 | ]; 101 | 102 | /// 八门(奇门遁甲) 103 | static let BA_MEN_QI_MEN: [String] = [ 104 | "休", 105 | "死", 106 | "伤", 107 | "杜", 108 | "", 109 | "开", 110 | "惊", 111 | "生", 112 | "景" 113 | ]; 114 | 115 | /// 太乙九神(太乙神数) 116 | static let NAME_TAI_YI: [String] = [ 117 | "太乙", 118 | "摄提", 119 | "轩辕", 120 | "招摇", 121 | "天符", 122 | "青龙", 123 | "咸池", 124 | "太阴", 125 | "天乙" 126 | ]; 127 | 128 | /// 太乙九神对应类型 129 | static let TYPE_TAI_YI: [String] = [ 130 | "吉神", 131 | "凶神", 132 | "安神", 133 | "安神", 134 | "凶神", 135 | "吉神", 136 | "凶神", 137 | "吉神", 138 | "吉神" 139 | ]; 140 | 141 | /// 太乙九神歌诀(太乙神数) 142 | static let SONG_TAI_YI: [String] = [ 143 | "门中太乙明,星官号贪狼,赌彩财喜旺,婚姻大吉昌,出入无阻挡,参谒见贤良,此行三五里,黑衣别阴阳。", 144 | "门前见摄提,百事必忧疑,相生犹自可,相克祸必临,死门并相会,老妇哭悲啼,求谋并吉事,尽皆不相宜,只可藏隐遁,若动伤身疾。", 145 | "出入会轩辕,凡事必缠牵,相生全不美,相克更忧煎,远行多不利,博彩尽输钱,九天玄女法,句句不虚言。", 146 | "招摇号木星,当之事莫行,相克行人阻,阴人口舌迎,梦寐多惊惧,屋响斧自鸣,阴阳消息理,万法弗违情。", 147 | "五鬼为天符,当门阴女谋,相克无好事,行路阻中途,走失难寻觅,道逢有尼姑,此星当门值,万事有灾除。", 148 | "神光跃青龙,财气喜重重,投入有酒食,赌彩最兴隆,更逢相生旺,休言克破凶,见贵安营寨,万事总吉同。", 149 | "吾将为咸池,当之尽不宜,出入多不利,相克有灾情,赌彩全输尽,求财空手回,仙人真妙语,愚人莫与知,动用虚惊退,反复逆风吹。", 150 | "坐临太阴星,百祸不相侵,求谋悉成就,知交有觅寻,回风归来路,恐有殃伏起,密语中记取,慎乎莫轻行。", 151 | "迎来天乙星,相逢百事兴,运用和合庆,茶酒喜相迎,求谋并嫁娶,好合有天成,祸福如神验,吉凶甚分明。" 152 | ]; 153 | 154 | /// 吉凶(玄空风水) 155 | static let LUCK_XUAN_KONG: [String] = [ 156 | "吉", 157 | "凶", 158 | "凶", 159 | "吉", 160 | "凶", 161 | "吉", 162 | "凶", 163 | "吉", 164 | "吉" 165 | ]; 166 | 167 | /// 吉凶(奇门遁甲) 168 | static let LUCK_QI_MEN: [String] = [ 169 | "大凶", 170 | "大凶", 171 | "小吉", 172 | "大吉", 173 | "大吉", 174 | "大吉", 175 | "小凶", 176 | "小吉", 177 | "小凶" 178 | ]; 179 | 180 | /// 阴阳(奇门遁甲) 181 | static let YIN_YANG_QI_MEN: [String] = [ 182 | "阳", 183 | "阴", 184 | "阳", 185 | "阳", 186 | "阳", 187 | "阴", 188 | "阴", 189 | "阳", 190 | "阴" 191 | ]; 192 | 193 | /// 序号,0到8 194 | var index: Int = 0; 195 | 196 | var number: String { 197 | get { 198 | return NineStar.NUMBER[index] 199 | } 200 | } 201 | 202 | var color: String { 203 | get { 204 | return NineStar.COLOR[index] 205 | } 206 | } 207 | 208 | var wuXing: String { 209 | get { 210 | return NineStar.WU_XING[index] 211 | } 212 | } 213 | 214 | var position: String { 215 | get { 216 | return NineStar.POSITION[index] 217 | } 218 | } 219 | 220 | var positionDesc: String? { 221 | get { 222 | return LunarUtil.POSITION_DESC[position] 223 | } 224 | } 225 | 226 | var nameInXuanKong: String { 227 | get { 228 | return NineStar.NAME_XUAN_KONG[index] 229 | } 230 | } 231 | 232 | var nameInBeiDou: String { 233 | get { 234 | return NineStar.NAME_BEI_DOU[index] 235 | } 236 | } 237 | 238 | var nameInQiMen: String { 239 | get { 240 | return NineStar.NAME_QI_MEN[index] 241 | } 242 | } 243 | 244 | var nameInTaiYi: String { 245 | get { 246 | return NineStar.NAME_TAI_YI[index] 247 | } 248 | } 249 | 250 | var luckInQiMen: String { 251 | get { 252 | return NineStar.LUCK_QI_MEN[index] 253 | } 254 | } 255 | 256 | var luckInXuanKong: String { 257 | get { 258 | return NineStar.LUCK_XUAN_KONG[index] 259 | } 260 | } 261 | 262 | var yinYangInQiMen: String { 263 | get { 264 | return NineStar.YIN_YANG_QI_MEN[index] 265 | } 266 | } 267 | 268 | var typeInTaiYi: String { 269 | get { 270 | return NineStar.TYPE_TAI_YI[index] 271 | } 272 | } 273 | 274 | var baMenInQiMen: String { 275 | get { 276 | NineStar.BA_MEN_QI_MEN[index] 277 | } 278 | } 279 | 280 | var songInTaiYi: String { 281 | get { 282 | NineStar.SONG_TAI_YI[index] 283 | } 284 | } 285 | 286 | 287 | 288 | func toString() -> String { 289 | return "\(number)\(color)\(wuXing)\(nameInBeiDou)" 290 | } 291 | 292 | func toFullString() -> String { 293 | var s: String = 294 | "\(number)\(color)\(wuXing) \(position)(\(positionDesc ?? ""))\(nameInBeiDou) 玄空[\(nameInXuanKong) \(luckInXuanKong)] 奇门[\(nameInQiMen) \(luckInQiMen)" 295 | if (baMenInQiMen.count > 0) { 296 | s += " \(baMenInQiMen)门" 297 | } 298 | s += " \(yinYangInQiMen)] 太乙[\(nameInTaiYi) \(typeInTaiYi)]" 299 | return s; 300 | } 301 | } 302 | 303 | -------------------------------------------------------------------------------- /Sources/SwiftLunar/Solar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Solar.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/11. 6 | // 7 | 8 | import Foundation 9 | 10 | // 阳历日期 11 | 12 | @available(watchOS 8.0, *) 13 | @available(iOS 15.0, *) 14 | @available(macOS 12.0, *) 15 | public struct Solar: Hashable { 16 | static let J2000: Double = 2451545 17 | 18 | public var year: Int = 0 19 | 20 | public var month: Int = 0 21 | 22 | public var day: Int = 0 23 | 24 | public var hour: Int = 0 25 | 26 | public var minute: Int = 0 27 | 28 | public var second:Int = 0 29 | 30 | public var isLeapYear: Bool { 31 | return SolarUtil.isLeapYear(year: self.year) 32 | } 33 | 34 | public var calendar: Date { 35 | get { 36 | // let dc = DateComponents(calendar: Calendar(identifier: .gregorian), year: year, month: month, day: day, hour: hour, minute: minute, second: second) 37 | return ExactDate.fromYmdHms(year: year, month: month, day: day, hour: hour, minute: minute, second: second) 38 | } 39 | set (date) { 40 | let setDate: Date = ExactDate.fromDate(date: date) 41 | // let dateCompment: DateComponents = Calendar(identifier: .gregorian).dateComponents([.year, .month, .day, .hour, .minute, .second], from: date) 42 | year = setDate.get(.year) //dateCompment.year! 43 | month = setDate.get(.month) //dateCompment.month! 44 | day = calcDay(day: setDate.get(.day)) 45 | hour = setDate.get(.hour) //dateCompment.hour! 46 | minute = setDate.get(.minute) // dateCompment.minute! 47 | second = setDate.get(.second) //dateCompment.second! 48 | } 49 | } 50 | 51 | public var julianDay: Double { 52 | get { 53 | var y: Int = year 54 | var m: Int = month 55 | let d: Double = Double(day) + ((Double(second) * 1.0 / 60 + Double(minute)) / 60 + Double(hour)) / 24 56 | var n: Int = 0 57 | var g: Bool = false 58 | if (y * 372 + m * 31 + Int(floor(d)) >= 588829) { 59 | g = true 60 | } 61 | if (m <= 2) { 62 | m += 12 63 | y -= 1 64 | } 65 | if (g) { 66 | n = Int(floor(Double(y) * 1.0 / 100)) 67 | n = 2 - n + Int(floor(Double(n) * 1.0 / 4)) 68 | } 69 | return floor(365.25 * (Double(y) + 4716)) + 70 | floor(30.6001 * (Double(m) + 1)) + 71 | d + 72 | Double(n) - 73 | 1524.5 74 | } 75 | set (julianDay) { 76 | var d: Int = Int(floor(julianDay + 0.5)) 77 | var f: Double = julianDay + 0.5 - Double(d) 78 | var c: Double 79 | 80 | if (d >= 2299161) { 81 | c = floor((Double(d) - 1867216.25) / 36524.25) 82 | d += Int(1 + c - floor(c * 1.0 / 4)) 83 | } 84 | d += 1524 85 | var year: Int = Int(floor((Double(d) - 122.1) / 365.25)) 86 | d -= Int(floor(365.25 * Double(year))) 87 | var month: Int = Int(floor(Double(d) * 1.0 / 30.601)) 88 | d -= Int(floor(30.601 * Double(month))) 89 | let day: Int = d 90 | if (month > 13) { 91 | month -= 13 92 | year -= 4715 93 | } else { 94 | month -= 1 95 | year -= 4716 96 | } 97 | f *= 24 98 | var hour: Int = Int(floor(f)) 99 | 100 | f -= Double(hour) 101 | f *= 60 102 | var minute: Int = Int(floor(f)) 103 | 104 | f -= Double(minute) 105 | f *= 60 106 | var second: Int = Int(round(f)) 107 | 108 | if (second > 59) { 109 | second -= 60 110 | minute += 1 111 | } 112 | if (minute > 59) { 113 | minute -= 60 114 | hour += 1 115 | } 116 | 117 | self.year = Int(year) 118 | self.month = Int(month) 119 | self.day = calcDay(day: Int(day)) 120 | self.hour = Int(hour) 121 | self.minute = Int(minute) 122 | self.second = Int(second) 123 | } 124 | } 125 | 126 | public init(fromYmd year: Int, month: Int, day: Int) { 127 | self.year = year 128 | self.month = month 129 | self.day = calcDay(day: day) 130 | } 131 | 132 | public init(fromYmdHms year: Int, month: Int, day: Int, hour: Int, minute: Int, second: Int) { 133 | self.year = year 134 | self.month = month 135 | self.day = calcDay(day: day) 136 | self.hour = hour 137 | self.minute = minute 138 | self.second = second 139 | } 140 | 141 | public init() { 142 | let date: Date = Date() 143 | self.calendar = date 144 | } 145 | 146 | public init(fromDate date: Date) { 147 | self.calendar = date 148 | } 149 | 150 | public init(fromJulianDay julianDay: Double) { 151 | self.julianDay = julianDay 152 | } 153 | 154 | // init(fromJulianDay julianDay: Double) { 155 | // var d: Double = (julianDay + 0.5) 156 | // var f: Double = julianDay + 0.5 - d 157 | // var c: Double 158 | // 159 | // if (d >= 2299161) { 160 | // c = ((d - 1867216.25) / 36524.25) 161 | // d += 1 + c - (c * 1.0 / 4) 162 | // } 163 | // d += 1524 164 | // var year: Double = ((d - 122.1) / 365.25) 165 | // d -= (365.25 * year) 166 | // var month: Double = (d * 1.0 / 30.601) 167 | // d -= (30.601 * month) 168 | // var day: Double = d 169 | // if (month > 13) { 170 | // month -= 13 171 | // year -= 4715 172 | // } else { 173 | // month -= 1 174 | // year -= 4716 175 | // } 176 | // f *= 24 177 | // var hour: Double = f 178 | // 179 | // f -= hour 180 | // f *= 60 181 | // var minute: Double = f 182 | // 183 | // f -= minute 184 | // f *= 60 185 | // var second: Double = f 186 | // 187 | // if (second > 59) { 188 | // second -= 60 189 | // minute += 1 190 | // } 191 | // if (minute > 59) { 192 | // minute -= 60 193 | // hour += 1 194 | // } 195 | // 196 | // self.calendar = ExactDate.fromYmdHms(year, month, day, hour, minute, second) 197 | // self.year = calendar.get(.year) 198 | // self.month = calendar.get(.month) 199 | // self.day = calendar.get(.day) 200 | // self.hour = calendar.get(.hour) 201 | // self.minute = calendar.get(.minute) 202 | // self.second = calendar.get(.second) 203 | // } 204 | 205 | // static List? getSolarfromBaZi( 206 | // {required String yearGanZhi, 207 | // required String monthGanZhi, 208 | // required String dayGanZhi, 209 | // required String timeGanZhi, 210 | // int sect = 2, 211 | // int baseYear = 1900, 212 | // int endYear = 2100}) { 213 | // List? l = [] 214 | // Solar today = Solar.fromDate(DateTime(endYear)) 215 | // Lunar lunar = today.getLunar() 216 | // 217 | // int offsetYear = LunarUtil.getJiaZiIndex(lunar.getYearInGanZhiExact()) - 218 | // LunarUtil.getJiaZiIndex(yearGanZhi) 219 | // if (offsetYear < 0) { 220 | // offsetYear = offsetYear + 60 221 | // } 222 | // int startYear = lunar.getYear() - offsetYear 223 | // int hour = 0 224 | // String timeZhi = timeGanZhi.substring(1) 225 | // for (int i = 0, j = LunarUtil.ZHI.length i < j i++) { 226 | // if (LunarUtil.ZHI[i] == timeZhi) { 227 | // hour = (i - 1) * 2 228 | // } 229 | // } 230 | // while (startYear >= baseYear) { 231 | // int year = startYear - 1 232 | // int counter = 0 233 | // int month = 12 234 | // int day 235 | // bool found = false 236 | // while (counter < 15) { 237 | // if (year >= baseYear) { 238 | // day = 1 239 | // Solar solar = Solar.fromYmdHms(year, month, day, hour, 0, 0) 240 | // lunar = solar.getLunar() 241 | // if (lunar.getYearInGanZhiExact() == yearGanZhi && 242 | // lunar.getMonthInGanZhiExact() == monthGanZhi) { 243 | // found = true 244 | // break 245 | // } 246 | // } 247 | // month++ 248 | // if (month > 12) { 249 | // month = 1 250 | // year++ 251 | // } 252 | // counter++ 253 | // } 254 | // 255 | // if (found) { 256 | // counter = 0 257 | // month-- 258 | // if (month < 1) { 259 | // month = 12 260 | // year-- 261 | // } 262 | // day = 1 263 | // Solar solar = Solar.fromYmdHms(year, month, day, hour, 0, 0) 264 | // while (counter < 61) { 265 | // lunar = solar.getLunar() 266 | // String dgz = (2 == sect) 267 | // ? lunar.getDayInGanZhiExact2() 268 | // : lunar.getDayInGanZhiExact() 269 | // if (lunar.getYearInGanZhiExact() == yearGanZhi && 270 | // lunar.getMonthInGanZhiExact() == monthGanZhi && 271 | // dgz == dayGanZhi && 272 | // lunar.getTimeInGanZhi() == timeGanZhi) { 273 | // l.add(solar) 274 | // break 275 | // } 276 | // solar = solar.next(1) 277 | // counter ++ 278 | // } 279 | // } 280 | // startYear -= 60 281 | // } 282 | // return l 283 | // } 284 | 285 | // int getYear() => _year //get method 286 | // 287 | // int getMonth() => _month 288 | // 289 | // int getDay() => _day 290 | // 291 | // int getHour() => _hour 292 | // 293 | // int getMinute() => _minute 294 | // 295 | // int getSecond() => _second 296 | // 297 | // DateTime getCalendar() => _calendar! 298 | 299 | 300 | func toString() -> String { 301 | return toYmd() 302 | } 303 | 304 | 305 | // func isLeapYear() -> Bool { 306 | // return SolarUtil.isLeapYear(year: year) 307 | // } 308 | 309 | // 获取星期,0代表周日,1代表周一 310 | // @return 0123456 311 | public var week: Int { 312 | var w: Int = Calendar(identifier: .gregorian).component(.weekday, from: calendar) - 1 313 | if (w == -1) { 314 | w = 0 315 | } 316 | return w 317 | } 318 | 319 | // 获取星期的中文 320 | // @return 日一二三四五六 321 | public var weekInChinese: String { 322 | return SolarUtil.WEEK[week] 323 | } 324 | 325 | /// 获取星座 326 | /// @return 星座 327 | public var constellation: String { 328 | var index: Int = 11 329 | let y: Int = month * 100 + day 330 | if (y >= 321 && y <= 419) { 331 | index = 0 332 | } else if (y >= 420 && y <= 520) { 333 | index = 1 334 | } else if (y >= 521 && y <= 621) { 335 | index = 2 336 | } else if (y >= 622 && y <= 722) { 337 | index = 3 338 | } else if (y >= 723 && y <= 822) { 339 | index = 4 340 | } else if (y >= 823 && y <= 922) { 341 | index = 5 342 | } else if (y >= 923 && y <= 1023) { 343 | index = 6 344 | } else if (y >= 1024 && y <= 1122) { 345 | index = 7 346 | } else if (y >= 1123 && y <= 1221) { 347 | index = 8 348 | } else if (y >= 1222 || y <= 119) { 349 | index = 9 350 | } else if (y <= 218) { 351 | index = 10 352 | } 353 | return SolarUtil.XING_ZUO[index] 354 | } 355 | 356 | /// 获取儒略日 357 | /// @return 儒略日 358 | // func getJulianDay() -> Double{ 359 | // var y: Int = year 360 | // var m: Int = month 361 | // var d: Double = day + ((second * 1.0 / 60 + minute) / 60 + hour) / 24 362 | // var n: Int = 0 363 | // var g: Bool = false 364 | // if (y * 372 + m * 31 + d.floor() >= 588829) { 365 | // g = true 366 | // } 367 | // if (m <= 2) { 368 | // m += 12 369 | // y -= 1 370 | // } 371 | // if (g) { 372 | // n = (y * 1.0 / 100).floor() 373 | // n = 2 - n + (n * 1.0 / 4).floor() 374 | // } 375 | // return ((365.25 * (y + 4716)).floor()) + 376 | // ((30.6001 * (m + 1)).floor()) + 377 | // d + 378 | // n - 379 | // 1524.5 380 | // } 381 | 382 | /// 获取节日,有可能一天会有多个节日 383 | /// @return 劳动节等 384 | public var festivals: [String] { 385 | var l: [String] = [] 386 | //获取几月几日对应的节日 387 | var f: String? = SolarUtil.FESTIVAL["\(month)-\(day)"] 388 | if (nil != f) { 389 | l.append(f!) 390 | } 391 | //计算几月第几个星期几对应的节日 392 | let weeks: Int = Int(ceil(Double(day) / 7.0)) 393 | //星期几,1代表星期天 394 | // let week: Int = eek() 395 | f = SolarUtil.WEEK_FESTIVAL["\(month)-\(weeks)-\(week)"] 396 | if (nil != f) { 397 | l.append(f!) 398 | } 399 | if (day + 7 > SolarUtil.getDaysOfMonth(year: year, month: month)) { 400 | f = SolarUtil.WEEK_FESTIVAL["\(month)-0-\(week)"] 401 | if (nil != f) { 402 | l.append(f!) 403 | } 404 | } 405 | return l 406 | } 407 | 408 | func calcDay(day: Int) -> Int { 409 | var newDay: Int = day 410 | if (year == 1582 && month == 10) { 411 | if (newDay >= 15) { 412 | newDay -= 10 413 | return newDay 414 | } 415 | } 416 | return newDay 417 | } 418 | /// 获取非正式的节日,有可能一天会有多个节日 419 | /// @return 非正式的节日列表,如中元节 420 | public var otherFestivals: [String] { 421 | var l: [String] = [] 422 | let fs: [String]? = SolarUtil.OTHER_FESTIVAL["\(month)-\(day)"] 423 | if (nil != fs) { 424 | l.append(contentsOf: fs!) 425 | } 426 | return l 427 | } 428 | 429 | /// 获取往后推几天的阳历日期,如果要往前推,则天数用负数 430 | /// @param days 天数 431 | /// @param onlyWorkday 是否仅限工作日 432 | /// @return 阳历日期 433 | public func next(days:Int, onlyWorkday: Bool = false) -> Solar { 434 | var c: Date = calendar 435 | let timeInterval: TimeInterval = Double(days * 86400) 436 | if (0 != days) { 437 | if (!onlyWorkday) { 438 | c.addTimeInterval(timeInterval) 439 | } else { 440 | var rest: Int = abs(days) 441 | let add: TimeInterval = days < 1 ? -86400 : 86400 442 | while (rest > 0) { 443 | c.addTimeInterval(add) 444 | var work: Bool = true 445 | let holiday: Holiday? = 446 | HolidayUtil.getHolidayByYmd(year: c.get(.year), month: c.get(.month), day: c.get(.day)) 447 | if (nil == holiday) { 448 | let week: Int = Calendar(identifier: .gregorian).component(.weekday, from: c) 449 | if (1 == week || 7 == week) { 450 | work = false 451 | } 452 | } else { 453 | work = holiday!.isWork 454 | } 455 | if (work) { 456 | rest-=1 457 | } 458 | } 459 | } 460 | } 461 | return Solar(fromDate: c) 462 | } 463 | 464 | public func toYmd() -> String { 465 | var d: Int = day 466 | if (year == 1582 && month == 10) { 467 | if (d >= 5) { 468 | d += 10 469 | } 470 | } 471 | var y: String = Swift.String(year) 472 | while (y.count < 4) { 473 | y = "0" + y 474 | } 475 | let dateFormat = DateFormatter() 476 | dateFormat.dateFormat = "yyyy-MM-dd" 477 | return dateFormat.string(from: calendar) 478 | // return calendar.formatted(.dateTime.locale(Locale(identifier: "zh_HK")).year(.defaultDigits).month(.twoDigits).day(.twoDigits)) 479 | } 480 | 481 | public func toYmdHms() -> String { 482 | let dateFormat = DateFormatter() 483 | dateFormat.dateFormat = "yyyy-MM-dd HH:mm:ss" 484 | return dateFormat.string(from: calendar) 485 | // return calendar.formatted(.dateTime.locale(Locale(identifier: "zh_CN")).year(.defaultDigits).month(.twoDigits).day(.twoDigits).hour(.twoDigits(amPM: .narrow)).minute(.twoDigits).second(.twoDigits)) 486 | } 487 | 488 | public func toHm() -> String { 489 | let dateFormat = DateFormatter() 490 | dateFormat.dateFormat = "HH:mm" 491 | return dateFormat.string(from: calendar) 492 | // return calendar.formatted(.dateTime.locale(Locale(identifier: "zh_CN")).hour(.twoDigits(amPM: .narrow)).minute(.twoDigits)) 493 | } 494 | 495 | func toFullString() -> String { 496 | var s: String = toYmdHms() 497 | if (isLeapYear) { 498 | s += " 闰年" 499 | } 500 | s += " 星期" + weekInChinese 501 | let festivals: [String] = festivals 502 | for festival in festivals { 503 | s += " (\(festival))" 504 | } 505 | s += " " + constellation + "座" 506 | return s 507 | } 508 | 509 | public func getLunar() -> Lunar { 510 | return Lunar(fromDate: calendar) 511 | } 512 | } 513 | 514 | extension Date { 515 | func get(_ components: Calendar.Component..., calendar: Calendar = Calendar.current) -> DateComponents { 516 | return calendar.dateComponents(Set(components), from: self) 517 | } 518 | 519 | func get(_ component: Calendar.Component, calendar: Calendar = Calendar.current) -> Int { 520 | return calendar.component(component, from: self) 521 | } 522 | } 523 | -------------------------------------------------------------------------------- /Sources/SwiftLunar/SolarHalfYear.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SolarHalfYear.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/19. 6 | // 7 | import Foundation 8 | 9 | // 阳历半年 10 | 11 | @available(watchOS 8.0, *) 12 | @available(iOS 15.0, *) 13 | @available(macOS 12.0, *) 14 | struct SolarHalfYear { 15 | /// 半年的月数 16 | static let MONTH_COUNT: Int = 6; 17 | 18 | /// 年 19 | var year: Int = 0; 20 | 21 | /// 月 22 | var month: Int = 0; 23 | 24 | var index: Int { 25 | get { 26 | Int(ceil(Double(month) * 1.0 / Double(SolarHalfYear.MONTH_COUNT))) 27 | } 28 | } 29 | 30 | var months: [SolarMonth] { 31 | get { 32 | var l: [SolarMonth] = [] 33 | let newIndex = self.index - 1 34 | for i in 0.. getMonths() { 59 | // List l = []; 60 | // int index = getIndex() - 1; 61 | // for (int i = 0; i < MONTH_COUNT; i++) { 62 | // l.add(SolarMonth.fromYm(_year, MONTH_COUNT * index + i + 1)); 63 | // } 64 | // return l; 65 | // } 66 | 67 | func next(halfYears: Int) -> SolarHalfYear { 68 | if (0 == halfYears) { 69 | return SolarHalfYear(year: year, month: month); 70 | } else { 71 | var rest: Int = halfYears * SolarHalfYear.MONTH_COUNT; 72 | var y: Int = year; 73 | y += Int(rest / 12) 74 | rest = rest % 12; 75 | var m: Int = month + rest; 76 | if (m > 12) { 77 | y += 1; 78 | m -= 12; 79 | } else if (m < 1) { 80 | y -= 1; 81 | m += 12; 82 | } 83 | return SolarHalfYear(year: y, month: m); 84 | } 85 | } 86 | 87 | func toString() -> String { 88 | return "\(year).\(index)" 89 | } 90 | 91 | func toFullString() -> String { 92 | return "\(year)年\(index == 1 ? "上" : "下")半年" 93 | } 94 | } 95 | 96 | -------------------------------------------------------------------------------- /Sources/SwiftLunar/SolarMonth.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SolarMonth.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/19. 6 | // 7 | import Foundation 8 | 9 | // 阳历月 10 | 11 | @available(watchOS 8.0, *) 12 | @available(iOS 15.0, *) 13 | @available(macOS 12.0, *) 14 | public struct SolarMonth { 15 | /// 年 16 | public var year: Int = 0; 17 | 18 | /// 月 19 | public var month: Int = 0; 20 | 21 | public var days: [Solar] { 22 | get { 23 | var l: [Solar] = []; 24 | let d: Solar = Solar(fromYmd: year, month: month, day: 1) 25 | l.append(d) 26 | let days: Int = SolarUtil.getDaysOfMonth(year: year, month: month); 27 | for i in 1.. _year; 58 | 59 | // int getMonth() => _month; 60 | 61 | // List getDays() { 62 | // List l = []; 63 | // Solar d = new Solar.fromYmd(_year, _month, 1); 64 | // l.add(d); 65 | // int days = SolarUtil.getDaysOfMonth(_year, _month); 66 | // for (int i = 1; i < days; i++) { 67 | // l.add(d.next(i)); 68 | // } 69 | // return l; 70 | // } 71 | 72 | public func next(quantity: Int) -> SolarMonth { 73 | if (0 == quantity) { 74 | return SolarMonth(year: year, month: month); 75 | } else { 76 | var rest: Int = quantity 77 | var y: Int = year; 78 | y += Int(rest / 12); 79 | rest = rest % 12; 80 | var m: Int = month + rest; 81 | if (m > 12) { 82 | y += 1; 83 | m -= 12; 84 | } else if (m < 1) { 85 | y -= 1; 86 | m += 12; 87 | } 88 | return SolarMonth(year: y, month: m); 89 | } 90 | } 91 | 92 | 93 | public func toString() -> String { 94 | return "\(year)-\(month)" 95 | } 96 | 97 | public func toFullString() -> String { 98 | return "\(year)年\(month)月" 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Sources/SwiftLunar/SolarSeason.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SolarSeason.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/21. 6 | // 7 | import Foundation 8 | 9 | @available(watchOS 8.0, *) 10 | @available(iOS 15.0, *) 11 | @available(macOS 12.0, *) 12 | struct SolarSeason { 13 | /// 一季度的月数 14 | static let MONTH_COUNT: Int = 3; 15 | 16 | /// 年 17 | var year: Int = 0; 18 | 19 | /// 月 20 | var month: Int = 0; 21 | 22 | 23 | init(year: Int, month: Int) { 24 | self.year = year 25 | self.month = month 26 | } 27 | 28 | init(fromDate date: Date) { 29 | self.year = date.get(.year); 30 | self.month = date.get(.month) 31 | } 32 | 33 | var index: Int { 34 | get { 35 | return Int(ceil(Double(month) * 1.0 / Double(SolarSeason.MONTH_COUNT))) 36 | } 37 | } 38 | 39 | var months: [SolarMonth] { 40 | get { 41 | var months: [SolarMonth] = [] 42 | let index = index - 1 43 | for i in 0.. SolarSeason { 51 | if (0 == seasons) { 52 | return self; 53 | } else { 54 | var rest: Int = seasons * SolarSeason.MONTH_COUNT 55 | var y: Int = year 56 | y += Int(floor(Double(rest) / 12)) 57 | rest = abs(rest % 12); 58 | var m: Int = month + rest 59 | if (m > 12) { 60 | y += 1 61 | m -= 12 62 | } else if (m < 1) { 63 | y -= 1 64 | m += 12 65 | } 66 | return SolarSeason(year: y, month: m); 67 | } 68 | } 69 | 70 | func toString() -> String { 71 | return "\(year).\(index)" 72 | } 73 | 74 | func toFullString() -> String { 75 | return "\(year)年\(index)季度" 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Sources/SwiftLunar/SolarWeek.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SolarWeek.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/19. 6 | // 7 | 8 | import Foundation 9 | 10 | // 阳历周 11 | @available(watchOS 8.0, *) 12 | @available(iOS 15.0, *) 13 | @available(macOS 12.0, *) 14 | public struct SolarWeek { 15 | 16 | private static let durationOfDay: Int = 86400 17 | /// 年 18 | public var year: Int = 0 19 | 20 | /// 月 21 | public var month: Int = 0 22 | 23 | /// 日 24 | public var day: Int = 0 25 | 26 | /// 星期几作为一周的开始,1234560分别代表星期一至星期天 27 | public var start: Int = 0 28 | 29 | var index: Int { 30 | get { 31 | let c: Date = ExactDate.fromYmd(year: year, month: month, day: 1) 32 | var firstDayWeek: Int = c.get(.weekday) - 1 33 | if (7 == firstDayWeek) { 34 | firstDayWeek = 0; 35 | } 36 | var offset: Int = firstDayWeek - start 37 | if (offset < 0) { 38 | offset += 7 39 | } 40 | return Int(ceil(Double(day + offset) / 7.0)) 41 | } 42 | } 43 | 44 | public init(year: Int, month: Int, day: Int, start: Int) { 45 | self.year = year 46 | self.month = month 47 | self.day = day 48 | self.start = start 49 | } 50 | 51 | public init(date: Date = Date(), start: Int = 0) { 52 | self.year = date.get(.year) 53 | self.month = date.get(.month) 54 | self.day = date.get(.day) 55 | self.start = start 56 | } 57 | 58 | public func next(weeks: Int, separateMonth: Bool) -> SolarWeek { 59 | if (0 == weeks) { 60 | return SolarWeek(year: year, month: month, day: day, start: start) 61 | } 62 | if (separateMonth) { 63 | var n: Int = weeks 64 | var c: Date = ExactDate.fromYmd(year: year, month: month, day: day) 65 | var week: SolarWeek = SolarWeek(date: c, start: start) 66 | var month: Int = month; 67 | let plus: Bool = n > 0; 68 | while (0 != n) { 69 | c = c.addingTimeInterval(TimeInterval((plus ? 7 : -7) * 86400)) 70 | week = SolarWeek(date: c, start: start); 71 | var weekMonth: Int = week.month; 72 | if (month != weekMonth) { 73 | let index: Int = week.index 74 | if (plus) { 75 | if (1 == index) { 76 | let firstDay: Solar = week.getFirstDay(); 77 | week = SolarWeek(year: firstDay.year, month: firstDay.month, 78 | day: firstDay.day, start: start) 79 | weekMonth = week.month 80 | } else { 81 | c = ExactDate.fromYmd(year: week.year, month: week.month, day: 1); 82 | week = SolarWeek(date:c, start: start) 83 | } 84 | } else { 85 | let size: Int = SolarUtil.getWeeksOfMonth(year: week.year, month: week.month, start: start) 86 | if (size == index) { 87 | let firstDay: Solar = week.getFirstDay() 88 | let lastDay: Solar = firstDay.next(days: 6) 89 | week = SolarWeek(year: lastDay.year, month: lastDay.month, 90 | day: lastDay.day, start: start) 91 | weekMonth = week.month; 92 | } else { 93 | c = ExactDate.fromYmd(year: week.year, month: week.month, 94 | day: SolarUtil.getDaysOfMonth(year: week.year, month: week.month)) 95 | week = SolarWeek(date:c, start: start) 96 | } 97 | } 98 | month = weekMonth 99 | } 100 | n -= plus ? 1 : -1; 101 | } 102 | return week 103 | } else { 104 | var c: Date = ExactDate.fromYmd(year: year, month: month, day: day) 105 | c = c.addingTimeInterval(TimeInterval(weeks * 7 * SolarWeek.durationOfDay)) 106 | return SolarWeek(date:c, start: start) 107 | } 108 | } 109 | 110 | public func getFirstDay() -> Solar { 111 | var c: Date = ExactDate.fromYmd(year: year, month: month, day: day); 112 | var week: Int = c.get(.weekday) - 1 113 | if (week == -1) { 114 | week = 0; 115 | } 116 | var prev: Int = week - start 117 | if (prev < 0) { 118 | prev += 7; 119 | } 120 | c = c.addingTimeInterval(TimeInterval(-prev * SolarWeek.durationOfDay)) 121 | return Solar(fromDate: c) 122 | } 123 | 124 | public func getFirstDayInMonth() -> Solar? { 125 | let days: [Solar] = getDays() 126 | for day in days { 127 | if (month == day.month) { 128 | return day 129 | } 130 | } 131 | return nil; 132 | } 133 | 134 | public func getDays() -> [Solar] { 135 | let firstDay: Solar = getFirstDay() 136 | var l: [Solar] = []; 137 | l.append(firstDay); 138 | for i in 1..<7 { 139 | l.append(firstDay.next(days: i)) 140 | } 141 | return l 142 | } 143 | 144 | public func getDaysInMonth() -> [Solar] { 145 | let days: [Solar] = self.getDays() 146 | var l: [Solar] = [] 147 | for day in days { 148 | if (month != day.month) { 149 | continue; 150 | } 151 | l.append(day) 152 | } 153 | return l; 154 | } 155 | 156 | // func getIndex() -> Int { 157 | // let c: Date = ExactDate.fromYmd(year: year, month: month, day: 1); 158 | // var firstDayWeek: Int = c.get(.weekday) - 1 159 | // if (7 == firstDayWeek) { 160 | // firstDayWeek = 0; 161 | // } 162 | // var offset: Int = firstDayWeek - start; 163 | // if (offset < 0) { 164 | // offset += 7 165 | // } 166 | // return Int(ceil(Double(day + offset) / 7.0)) 167 | // } 168 | 169 | func getIndexInYear() -> Int { 170 | let c: Date = ExactDate.fromYmd(year: year, month: 1, day: 1); 171 | var firstDayWeek: Int = c.get(.weekday) - 1 172 | if (-1 == firstDayWeek) { 173 | firstDayWeek = 0 174 | } 175 | var offset: Int = firstDayWeek - start; 176 | if (offset < 0) { 177 | offset += 7 178 | } 179 | return Int(ceil(Double(SolarUtil.getDaysInYear(year: year, month: month, day: day) + offset) / 7.0)) 180 | 181 | } 182 | 183 | 184 | func toString() -> String { 185 | return "\(year).\(month).\(index)" 186 | } 187 | 188 | func toFullString() -> String { 189 | return "\(year)年\(month)月第\(index)周" 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /Sources/SwiftLunar/SolarYear.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SolarYear.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/20. 6 | // 7 | import Foundation 8 | // 阳历年 9 | @available(watchOS 8.0, *) 10 | @available(iOS 15.0, *) 11 | @available(macOS 12.0, *) 12 | struct SolarYear { 13 | /// 一年的月数 14 | static let MONTH_COUNT: Int = 12; 15 | 16 | /// 年 17 | var year: Int = 0; 18 | 19 | init(year: Int) { 20 | self.year = year 21 | } 22 | 23 | init(date: Date = Date()) { 24 | self.year = ExactDate.fromDate(date: date).get(.year) 25 | } 26 | 27 | // SolarYear() : this.fromDate(DateTime.now()); 28 | // 29 | // SolarYear.fromYear(int year) { 30 | // _year = year; 31 | // } 32 | // 33 | // SolarYear.fromDate(DateTime date) { 34 | // _year = ExactDate.fromDate(date).year; 35 | // } 36 | 37 | // int getYear() => _year; 38 | 39 | func getMonths() -> [SolarMonth] { 40 | var l: [SolarMonth] = [] 41 | let m: SolarMonth = SolarMonth(year: year, month: 1) 42 | l.append(m); 43 | for i in 1.. SolarYear { 50 | return SolarYear(year: year + quantity) 51 | } 52 | 53 | 54 | func toString() -> String { 55 | return "\(year)" 56 | } 57 | 58 | func toFullString() -> String { 59 | return "\(year)年" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Sources/SwiftLunar/Taoist.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Taoist.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/23. 6 | // 7 | @available(watchOS 8.0, *) 8 | @available(iOS 15.0, *) 9 | @available(macOS 12.0, *) 10 | struct Taoist { 11 | static let BIRTH_YEAR: Int = -2697 12 | 13 | /// 阴历 14 | var lunar: Lunar? 15 | 16 | static func fromLunar(lunar: Lunar) -> Taoist{ 17 | return Taoist(lunar: lunar) 18 | } 19 | 20 | static func fromYmdHms(year: Int, month: Int, day: Int, hour: Int, minute: Int, second: Int) -> Taoist { 21 | return fromLunar( 22 | lunar: SwiftLunar.Lunar(fromYmdHms: year + BIRTH_YEAR, lunarMonth: month, lunarDay: day, hour: hour, minute: minute, second: second)); 23 | } 24 | 25 | static func fromYmd(year: Int, month: Int, day: Int) -> Taoist { 26 | return fromYmdHms(year: year, month: month, day: day, hour: 0, minute: 0, second: 0); 27 | } 28 | 29 | var year: Int { 30 | get { 31 | return lunar!.year - Taoist.BIRTH_YEAR 32 | } 33 | } 34 | 35 | var month: Int { 36 | get { 37 | return lunar!.month 38 | } 39 | } 40 | 41 | var day: Int { 42 | get { 43 | return lunar!.day 44 | } 45 | } 46 | 47 | var yearInChinese: String { 48 | get { 49 | let y: String = Swift.String(year) 50 | var s: String = "" 51 | for v in y.utf16 { 52 | s += LunarUtil.NUMBER[Int(v) - 48] 53 | } 54 | return s 55 | } 56 | } 57 | 58 | var monthInChinese: String { 59 | get { 60 | return lunar!.getMonthInChinese() 61 | } 62 | } 63 | 64 | var dayInChinese: String { 65 | get { 66 | lunar!.getDayInChinese() 67 | } 68 | } 69 | 70 | func getFestivals() -> [TaoistFestival] { 71 | var l: [TaoistFestival] = []; 72 | let fs: [TaoistFestival]? = TaoistUtil.FESTIVAL["\(month)-\(day)"] 73 | if (nil != fs) { 74 | l.append(contentsOf: fs!) 75 | } 76 | let solarTerm: String = lunar!.getJieQi() 77 | if (solarTerm == "冬至") { 78 | l.append(TaoistFestival(name: "元始天尊圣诞")) 79 | } else if (solarTerm == "夏至") { 80 | l.append(TaoistFestival(name: "灵宝天尊圣诞")) 81 | } 82 | // 八节日 83 | var f: String? = TaoistUtil.BA_JIE[solarTerm] 84 | if (f != nil) { 85 | l.append(TaoistFestival(name: f!)) 86 | } 87 | // 八会日 88 | f = TaoistUtil.BA_HUI[lunar!.getDayInGanZhi()] 89 | if (f != nil) { 90 | l.append(TaoistFestival(name: f!)) 91 | } 92 | return l; 93 | } 94 | 95 | func isDayIn(days: [String]) -> Bool { 96 | let md: String = "\(month)-\(day)" 97 | for day in days { 98 | if (md == day) { 99 | return true; 100 | } 101 | } 102 | return false; 103 | } 104 | 105 | var isDaySanHuiL: Bool { 106 | get { 107 | return isDayIn(days: TaoistUtil.SAN_HUI) 108 | } 109 | } 110 | 111 | var isDaySanYuan: Bool { 112 | get { 113 | return isDayIn(days: TaoistUtil.SAN_YUAN) 114 | } 115 | } 116 | 117 | var isDayBaJie: Bool { 118 | get { 119 | return TaoistUtil.BA_JIE.keys.contains(lunar!.getJieQi()) 120 | } 121 | } 122 | 123 | var isDayWuLa: Bool { 124 | get { 125 | return isDayIn(days: TaoistUtil.WU_LA) 126 | 127 | } 128 | } 129 | 130 | var isDayBaHui: Bool { 131 | get { 132 | return TaoistUtil.BA_HUI.keys.contains(lunar!.getDayInGanZhi()) 133 | } 134 | } 135 | 136 | var isDayMingWu:Bool { 137 | get { 138 | return "戊" == lunar!.getDayGan() 139 | } 140 | } 141 | 142 | var isDayAnWu: Bool { 143 | get { 144 | return lunar!.getDayZhi() == TaoistUtil.AN_WU[abs(month) - 1] 145 | } 146 | } 147 | 148 | var isDayWu: Bool { 149 | get { 150 | return isDayMingWu || isDayAnWu 151 | } 152 | } 153 | 154 | var isDayTianShe: Bool { 155 | get { 156 | var ret: Bool = false; 157 | let monthRoot: String = lunar!.getMonthZhi() 158 | let dayColumn: String = lunar!.getDayInGanZhi(); 159 | if ("寅卯辰".contains(monthRoot)) { 160 | if ("戊寅" == dayColumn) { 161 | ret = true; 162 | } 163 | } else if ("巳午未".contains(monthRoot)) { 164 | if ("甲午" == dayColumn) { 165 | ret = true; 166 | } 167 | } else if ("申酉戌".contains(monthRoot)) { 168 | if ("戊申" == dayColumn) { 169 | ret = true; 170 | } 171 | } else if ("亥子丑".contains(monthRoot)) { 172 | if ("甲子" == dayColumn) { 173 | ret = true; 174 | } 175 | } 176 | return ret; 177 | } 178 | } 179 | 180 | func toString() -> String { 181 | return "\(yearInChinese)年\(monthInChinese)月\(dayInChinese)"; 182 | } 183 | 184 | func toFullString() -> String { 185 | return "道歷\(yearInChinese)年,天運\(lunar!.getYearInGanZhi())年,\(lunar!.getMonthInGanZhi())月,\(lunar!.getDayInGanZhi())日。\(monthInChinese)月\(dayInChinese)日,\(lunar!.getTimeZhi())時。" 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /Sources/SwiftLunar/TaoistFestival.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/23. 6 | // 7 | /// 道历节日 8 | struct TaoistFestival { 9 | /// 名称 10 | var name: String 11 | 12 | /// 备注 13 | var remark: String 14 | 15 | init(name: String, remark: String = "") { 16 | self.name = name; 17 | self.remark = remark 18 | } 19 | 20 | func toString() -> String { 21 | return name 22 | } 23 | 24 | func toFullString() -> String { 25 | var s: String = name 26 | if (remark.count > 0) { 27 | s += "[" 28 | s += remark 29 | s += "]" 30 | } 31 | return s 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /Sources/SwiftLunar/Timeset.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Timeset.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/14. 6 | // 7 | // Timeset 8 | import Foundation 9 | 10 | @available(watchOS 8.0, *) 11 | @available(iOS 15.0, *) 12 | @available(macOS 12.0, *) 13 | public struct Timeset { 14 | /// 月支,按正月起寅排列 15 | static let MONTH_ZHI: [String] = [ 16 | "", 17 | "寅", 18 | "卯", 19 | "辰", 20 | "巳", 21 | "午", 22 | "未", 23 | "申", 24 | "酉", 25 | "戌", 26 | "亥", 27 | "子", 28 | "丑" 29 | ] 30 | 31 | /// 长生十二神 32 | static let CHANG_SHENG: [String] = [ 33 | "长生", 34 | "沐浴", 35 | "冠带", 36 | "临官", 37 | "帝旺", 38 | "衰", 39 | "病", 40 | "死", 41 | "墓", 42 | "绝", 43 | "胎", 44 | "养" 45 | ] 46 | 47 | /// 长生十二神日干偏移值,五阳干顺推,五阴干逆推 48 | static let CHANG_SHENG_OFFSET: [String: Int] = [ 49 | "甲": 1, 50 | "丙": 10, 51 | "戊": 10, 52 | "庚": 7, 53 | "壬": 4, 54 | "乙": 6, 55 | "丁": 9, 56 | "己": 9, 57 | "辛": 0, 58 | "癸": 3 59 | ] 60 | 61 | /// 流派,2晚子时日柱按当天,1晚子时日柱按明天 62 | public var genre: Int = 1 63 | 64 | /// 阴历 65 | public var lunar: Lunar; 66 | 67 | public init(lunar: Lunar) { 68 | self.lunar = lunar 69 | } 70 | 71 | public init(lunar: Lunar, genre: Int) { 72 | self.lunar = lunar 73 | self.genre = genre 74 | } 75 | 76 | // int getSect() => _sect; 77 | 78 | // void setSect(int sect) { 79 | // _sect = (1 == sect) ? 1 : 2; 80 | // } 81 | 82 | public func getLunar() -> Lunar { 83 | return lunar 84 | } 85 | 86 | public func getYear() -> String { 87 | return lunar.getYearInGanZhiExact() 88 | } 89 | 90 | public func getYearGan() -> String { 91 | return lunar.getYearGanExact() 92 | } 93 | 94 | public func getYearZhi() -> String { 95 | return lunar.getYearZhiExact() 96 | } 97 | 98 | public func getYearHideGan() -> [String] { 99 | return LunarUtil.ZHI_HIDE_GAN[getYearZhi()]! 100 | } 101 | 102 | public func getYearWuXing() -> String { 103 | return "\(LunarUtil.WU_XING_GAN[getYearGan()]!)\(LunarUtil.WU_XING_ZHI[getYearZhi()]!)" 104 | } 105 | 106 | public func getYearNaYin() -> String { 107 | return LunarUtil.NAYIN[getYear()]! 108 | } 109 | 110 | public func getYearShiShenGan(isShort: Bool = false) -> String { 111 | if (isShort) { 112 | return LunarUtil.SHI_SHEN_GAN_SHORT["\(getDayGan())\(getYearGan())"]! 113 | } 114 | return LunarUtil.SHI_SHEN_GAN["\(getDayGan())\(getYearGan())"]! 115 | } 116 | 117 | public func getShiShenZhi(zhi: String, isShort: Bool) -> [String] { 118 | let hideGan: [String] = LunarUtil.ZHI_HIDE_GAN[zhi]!; 119 | var l: [String] = []; 120 | for gan in hideGan { 121 | if (isShort) { 122 | l.append(LunarUtil.SHI_SHEN_ZHI_SHORT["\(getDayGan())\(zhi)\(gan)"]!) 123 | } else { 124 | l.append(LunarUtil.SHI_SHEN_ZHI["\(getDayGan())\(zhi)\(gan)"]!) 125 | } 126 | } 127 | return l; 128 | } 129 | 130 | public func getShiShenGan(stem: String, isShort: Bool) -> String { 131 | if (isShort) { 132 | return LunarUtil.SHI_SHEN_GAN_SHORT["\(getDayGan())\(stem)"]! 133 | } 134 | return LunarUtil.SHI_SHEN_GAN["\(getDayGan())\(stem)"]! 135 | } 136 | 137 | public func getYearShiShenZhi(isShort: Bool = false) -> [String] { 138 | return getShiShenZhi(zhi: getYearZhi(), isShort: isShort) 139 | } 140 | 141 | func getDayGanIndex() -> Int { 142 | return genre == 2 ? lunar.getDayGanIndexExact2() : lunar.getDayGanIndexExact() 143 | } 144 | 145 | func getDayZhiIndex() -> Int { 146 | return genre == 2 ? lunar.getDayZhiIndexExact2() : lunar.getDayZhiIndexExact() 147 | } 148 | 149 | public func getDiShi(zhiIndex: Int) -> String { 150 | let offset: Int? = Timeset.CHANG_SHENG_OFFSET[getDayGan()] 151 | var index: Int = offset! + (getDayGanIndex() % 2 == 0 ? zhiIndex : -zhiIndex) 152 | if (index >= 12) { 153 | index -= 12 154 | } 155 | if (index < 0) { 156 | index += 12 157 | } 158 | return Timeset.CHANG_SHENG[index]; 159 | } 160 | 161 | public func getYearDiShi() -> String { 162 | return getDiShi(zhiIndex: lunar.getYearZhiIndexExact()) 163 | } 164 | 165 | public func getMonth() -> String { 166 | return lunar.getMonthInGanZhiExact() 167 | } 168 | 169 | public func getMonthGan() -> String { 170 | return lunar.getMonthGanExact() 171 | } 172 | 173 | public func getMonthZhi() -> String { 174 | return lunar.getMonthZhiExact() 175 | } 176 | 177 | public func getMonthHideGan() -> [String] { 178 | return LunarUtil.ZHI_HIDE_GAN[getMonthZhi()]! 179 | } 180 | 181 | public func getMonthWuXing() -> String { 182 | return "\(LunarUtil.WU_XING_GAN[getMonthGan()]!)\(LunarUtil.WU_XING_ZHI[getMonthZhi()]!)" 183 | } 184 | 185 | public func getMonthNaYin() -> String { 186 | return LunarUtil.NAYIN[getMonth()]! 187 | } 188 | 189 | public func getMonthShiShenGan(isShort: Bool = false) -> String { 190 | if (isShort) { 191 | return LunarUtil.SHI_SHEN_GAN_SHORT["\(getDayGan())\(getMonthGan())"]! 192 | } 193 | return LunarUtil.SHI_SHEN_GAN["\(getDayGan())\(getMonthGan())"]! 194 | } 195 | 196 | public func getMonthShiShenZhi(isShort: Bool = false) -> [String] { 197 | return getShiShenZhi(zhi: getMonthZhi(), isShort: isShort) 198 | } 199 | 200 | public func getMonthDiShi() -> String { 201 | return getDiShi(zhiIndex: lunar.getMonthZhiIndexExact()) 202 | } 203 | 204 | public func getDay() -> String { 205 | return genre == 2 ? lunar.getDayInGanZhiExact2() : lunar.getDayInGanZhiExact() 206 | } 207 | 208 | public func getDayGan() -> String { 209 | return genre == 2 ? lunar.getDayGanExact2() : lunar.getDayGanExact() 210 | } 211 | 212 | public func getDayZhi() -> String { 213 | return genre == 2 ? lunar.getDayZhiExact2() : lunar.getDayZhiExact() 214 | } 215 | 216 | public func getDayHideGan() -> [String] { 217 | return LunarUtil.ZHI_HIDE_GAN[getDayZhi()]! 218 | } 219 | 220 | public func getDayWuXing() -> String { 221 | return "\(LunarUtil.WU_XING_GAN[getDayGan()]!)\(LunarUtil.WU_XING_ZHI[getDayZhi()]!)" 222 | } 223 | 224 | public func getDayNaYin() -> String { 225 | return LunarUtil.NAYIN[getDay()]! 226 | } 227 | 228 | public func getDayShiShenGan() -> String { 229 | return "日元" 230 | } 231 | 232 | public func getDayShiShenZhi(isShort: Bool = false) -> [String] { 233 | return getShiShenZhi(zhi: getDayZhi(), isShort: isShort) 234 | } 235 | 236 | public func getDayDiShi() -> String { 237 | return getDiShi(zhiIndex: getDayZhiIndex()) 238 | } 239 | 240 | public func getTime() -> String { 241 | return lunar.getTimeInGanZhi() 242 | } 243 | 244 | public func getTimeGan() -> String { 245 | return lunar.getTimeGan() 246 | } 247 | 248 | public func getTimeZhi() -> String { 249 | return lunar.getTimeZhi() 250 | } 251 | 252 | public func getTimeHideGan() -> [String] { 253 | return LunarUtil.ZHI_HIDE_GAN[getTimeZhi()]! 254 | } 255 | 256 | public func getTimeWuXing() -> String { 257 | return "\(LunarUtil.WU_XING_GAN[getTimeGan()]!)\(LunarUtil.WU_XING_ZHI[getTimeZhi()]!)" 258 | } 259 | 260 | public func getTimeNaYin() -> String { 261 | return LunarUtil.NAYIN[getTime()]! 262 | } 263 | 264 | public func getTimeShiShenGan(isShort: Bool = false) -> String { 265 | if (isShort) { 266 | return LunarUtil.SHI_SHEN_GAN_SHORT["\(getDayGan())\(getTimeGan())"]! 267 | } 268 | return LunarUtil.SHI_SHEN_GAN["\(getDayGan())\(getTimeGan())"]! 269 | } 270 | 271 | public func getTimeShiShenZhi(isShort: Bool = false) -> [String] { 272 | getShiShenZhi(zhi: getTimeZhi(), isShort: isShort) 273 | } 274 | 275 | public func getTimeDiShi() -> String { 276 | getDiShi(zhiIndex: lunar.getTimeZhiIndex()) 277 | } 278 | 279 | public func getTaiYuan() -> String { 280 | var ganIndex: Int = lunar.getMonthGanIndexExact() + 1; 281 | if (ganIndex >= 10) { 282 | ganIndex -= 10; 283 | } 284 | var zhiIndex: Int = lunar.getMonthZhiIndexExact() + 3; 285 | if (zhiIndex >= 12) { 286 | zhiIndex -= 12; 287 | } 288 | return "\(LunarUtil.GAN[ganIndex + 1])\(LunarUtil.ZHI[zhiIndex + 1])" 289 | } 290 | 291 | func getTaiYuanNaYin() -> String { 292 | return LunarUtil.NAYIN[getTaiYuan()]! 293 | } 294 | 295 | public func getTaiXi() -> String { 296 | let ganIndex: Int = (genre == 2) ? lunar.getDayGanIndexExact2() : lunar.getDayGanIndexExact(); 297 | let zhiIndex: Int = (genre == 2) ? lunar.getDayZhiIndexExact2() : lunar.getDayZhiIndexExact(); 298 | 299 | return "\(LunarUtil.HE_GAN_5[ganIndex])\(LunarUtil.HE_ZHI_6[zhiIndex])" 300 | } 301 | 302 | public func getTaiXiNaYin() -> String { 303 | return LunarUtil.NAYIN[getTaiXi()]! 304 | } 305 | 306 | func getMingGong() -> String { 307 | var monthZhiIndex: Int = 0 308 | var timeZhiIndex: Int = 0 309 | for i in 0.. 12) { 320 | zhiIndex -= 12; 321 | } 322 | 323 | var jiaZiIndex: Int = LunarUtil.getJiaZiIndex(ganZhi: lunar.getMonthInGanZhiExact()) - (monthZhiIndex - zhiIndex); 324 | if (jiaZiIndex >= 60) { 325 | jiaZiIndex -= 60; 326 | } 327 | if (jiaZiIndex < 0) { 328 | jiaZiIndex += 60; 329 | } 330 | return LunarUtil.JIA_ZI[jiaZiIndex]; 331 | } 332 | 333 | public func getMingGongNaYin() -> String { 334 | return LunarUtil.NAYIN[getMingGong()]! 335 | } 336 | 337 | public func getShenGong() -> String { 338 | var monthZhiIndex: Int = 0; 339 | var timeZhiIndex: Int = 0; 340 | for i in 0.. 12) { 351 | zhiIndex -= 12; 352 | } 353 | var jiaZiIndex: Int = LunarUtil.getJiaZiIndex(ganZhi: lunar.getMonthInGanZhiExact()) - (monthZhiIndex - zhiIndex) 354 | if (jiaZiIndex >= 60) { 355 | jiaZiIndex -= 60; 356 | } 357 | if (jiaZiIndex < 0) { 358 | jiaZiIndex += 60; 359 | } 360 | return LunarUtil.JIA_ZI[jiaZiIndex]; 361 | } 362 | 363 | public func getShenGongNaYin() -> String { 364 | return LunarUtil.NAYIN[getShenGong()]! 365 | } 366 | 367 | public func getYun(gender: Int, genre: Int = 1) -> Yun { 368 | return Yun(lunar: lunar, gender: gender, genre: genre) 369 | } 370 | 371 | public func getYearXun() -> String { 372 | return lunar.getYearXunExact() 373 | } 374 | 375 | public func getYearXunKong() -> String { 376 | return lunar.getYearXunKongExact() 377 | } 378 | 379 | public func getMonthXun() -> String { 380 | return lunar.getMonthXunExact() 381 | } 382 | 383 | public func getMonthXunKong() -> String { 384 | return lunar.getMonthXunKongExact() 385 | } 386 | 387 | public func getDayXun() -> String { 388 | return genre == 2 ? lunar.getDayXunExact2() : lunar.getDayXunExact() 389 | } 390 | 391 | public func getDayXunKong() -> String { 392 | return genre == 2 ? lunar.getDayXunKongExact2() : lunar.getDayXunKongExact() 393 | } 394 | 395 | public func getTimeXun() -> String { 396 | return lunar.getTimeXun() 397 | } 398 | 399 | public func getTimeXunKong() -> String { 400 | return lunar.getTimeXunKong() 401 | } 402 | 403 | func toString() -> String { 404 | return "\(getYear()) \(getMonth()) \(getDay()) \(getTime())" 405 | } 406 | } 407 | -------------------------------------------------------------------------------- /Sources/SwiftLunar/Timeset/DaYun.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DaYun.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/19. 6 | // 7 | // Episode 8 | 9 | @available(watchOS 8.0, *) 10 | @available(iOS 15.0, *) 11 | @available(macOS 12.0, *) 12 | public struct DaYun: Hashable { 13 | /// 开始年(含) 14 | public var startYear: Int = 0 15 | 16 | /// 结束年(含) 17 | public var endYear: Int = 0 18 | 19 | /// 开始年龄(含) 20 | public var startAge: Int = 0 21 | 22 | /// 结束年龄(含) 23 | public var endAge: Int = 0 24 | 25 | /// 序数,0-9 26 | public var index: Int = 0 { 27 | didSet { 28 | calcProperties(yun: yun!, index: index) 29 | } 30 | } 31 | 32 | /// 运 33 | public var yun: Yun? { 34 | didSet { 35 | calcProperties(yun: yun!, index: index) 36 | } 37 | } 38 | 39 | /// 阴历 40 | public var lunar: Lunar? 41 | 42 | public init(yun: Yun, index: Int) { 43 | self.yun = yun 44 | self.index = index 45 | calcProperties(yun: yun, index: index) 46 | } 47 | 48 | mutating func calcProperties(yun: Yun, index: Int) { 49 | // _yun = yun; 50 | self.lunar = yun.lunar 51 | // _index = index; 52 | let birthYear: Int = lunar!.getSolar().year; 53 | let year: Int = yun.getStartSolar().year; 54 | if (index < 1) { 55 | startYear = birthYear; 56 | startAge = 1; 57 | endYear = year - 1; 58 | endAge = year - birthYear; 59 | } else { 60 | let add: Int = (index - 1) * 10; 61 | startYear = year + add; 62 | startAge = startYear - birthYear + 1; 63 | endYear = startYear + 9; 64 | endAge = startAge + 9; 65 | } 66 | } 67 | 68 | // int getStartYear() => _startYear; 69 | // 70 | // int getEndYear() => _endYear; 71 | // 72 | // int getStartAge() => _startAge; 73 | // 74 | // int getEndAge() => _endAge; 75 | // 76 | // int getIndex() => _index; 77 | // 78 | // Lunar getLunar() => _lunar!; 79 | 80 | public func getGanZhi() -> String { 81 | if (index < 1) { 82 | return "" 83 | } 84 | var offset: Int = LunarUtil.getJiaZiIndex(ganZhi: lunar!.getMonthInGanZhiExact()); 85 | offset += yun!.isGoWith ? index : -index; 86 | let size: Int = LunarUtil.JIA_ZI.count; 87 | if (offset >= size) { 88 | offset -= size 89 | } 90 | if (offset < 0) { 91 | offset += size 92 | } 93 | return LunarUtil.JIA_ZI[offset]; 94 | } 95 | 96 | public func getGan() -> String { 97 | let characters = Array(getGanZhi()) 98 | return String(characters[0]) 99 | } 100 | 101 | public func getZhi() -> String { 102 | let characters = Array(getGanZhi()) 103 | return String(characters[1]) 104 | } 105 | 106 | public func getXun() -> String { 107 | return LunarUtil.getXun(ganZhi: getGanZhi()) 108 | } 109 | 110 | public func getXunKong() -> String { 111 | return LunarUtil.getXunKong(ganZhi: getGanZhi()) 112 | } 113 | 114 | /// 获取10轮流年 115 | public func getLiuNian() -> [LiuNian] { 116 | return getLiuNianBy(n: 10) 117 | } 118 | 119 | /// 获取流年 120 | /// [n] 轮数 121 | public func getLiuNianBy(n: Int) -> [LiuNian] { 122 | var num: Int = n 123 | if (index < 1) { 124 | num = endYear - startYear + 1 125 | } 126 | var l: [LiuNian] = []; 127 | for i in 0.. [XiaoYun] { 135 | return getXiaoYunBy(n: 10); 136 | } 137 | 138 | /// 获取小运 139 | /// [n] 轮数 140 | public func getXiaoYunBy(n: Int) -> [XiaoYun] { 141 | var num: Int = n 142 | if (index < 1) { 143 | num = endYear - startYear + 1; 144 | } 145 | var l: [XiaoYun] = []; 146 | for i in 0.. String { 47 | return LunarUtil.MONTH[index + 1] 48 | } 49 | 50 | // int getIndex() => _index; 51 | // 52 | // int getYear() => _year; 53 | // 54 | // int getAge() => _age; 55 | 56 | public func getGanZhi() -> String { 57 | // 干支与出生日期和起运日期都没关系 58 | var offset: Int = LunarUtil.getJiaZiIndex(ganZhi: lunar!.getJieQiTable()["立春"]!.getLunar().getYearInGanZhiExact()) + index; 59 | if (daYun!.index > 0) { 60 | offset += daYun!.startAge - 1; 61 | } 62 | offset %= LunarUtil.JIA_ZI.count; 63 | return LunarUtil.JIA_ZI[offset]; 64 | } 65 | 66 | public func getGan() -> String { 67 | let characters = Array(getGanZhi()) 68 | return String(characters[0]) 69 | } 70 | 71 | public func getZhi() -> String { 72 | let characters = Array(getGanZhi()) 73 | return String(characters[1]) 74 | } 75 | 76 | public func getXun() -> String { 77 | return LunarUtil.getXun(ganZhi: getGanZhi()) 78 | } 79 | 80 | public func getXunKong() -> String { 81 | return LunarUtil.getXunKong(ganZhi: getGanZhi()) 82 | } 83 | 84 | public func getLiuYue() -> [LiuYue] { 85 | let n: Int = 12 86 | var l: [LiuYue] = [] 87 | for i in 0.. String { 19 | return LunarUtil.MONTH[index + 1] 20 | } 21 | 22 | public func getGanZhi() -> String { 23 | let gan: String = getGan() 24 | let zhi: String = getZhi() 25 | return gan + zhi; 26 | } 27 | 28 | public func getGan() -> String { 29 | var offset: Int = 0; 30 | let yearGan: String = String(liuNian.getGanZhi().prefix(1)); 31 | if ("甲" == yearGan || "己" == yearGan) { 32 | offset = 2 33 | } else if ("乙" == yearGan || "庚" == yearGan) { 34 | offset = 4 35 | } else if ("丙" == yearGan || "辛" == yearGan) { 36 | offset = 6 37 | } else if ("丁" == yearGan || "壬" == yearGan) { 38 | offset = 8 39 | } 40 | let gan: String = LunarUtil.GAN[(index + offset) % 10 + 1]; 41 | return gan; 42 | } 43 | 44 | public func getZhi() -> String { 45 | let zhi: String = LunarUtil.ZHI[(index + LunarUtil.BASE_MONTH_ZHI_INDEX) % 12 + 1]; 46 | return zhi; 47 | } 48 | 49 | public func getXun() -> String { 50 | return LunarUtil.getXun(ganZhi: getGanZhi()) 51 | } 52 | 53 | public func getXunKong() -> String { 54 | return LunarUtil.getXunKong(ganZhi: getGanZhi()) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Sources/SwiftLunar/Timeset/XiaoYun.swift: -------------------------------------------------------------------------------- 1 | // 2 | // XiaoYun.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/19. 6 | // 7 | // 小运 8 | @available(watchOS 8.0, *) 9 | @available(iOS 15.0, *) 10 | @available(macOS 12.0, *) 11 | public struct XiaoYun { 12 | /// 序数,0-9 13 | public var index: Int = 0 { 14 | didSet { 15 | year = daYun!.startYear + index 16 | age = daYun!.startAge + index 17 | } 18 | } 19 | 20 | /// 年 21 | public var year: Int = 0 22 | 23 | /// 年龄 24 | public var age: Int = 0 25 | 26 | /// 是否顺推 27 | var isGoWith: Bool = false 28 | 29 | /// 大运 30 | public var daYun: DaYun? { 31 | didSet { 32 | lunar = daYun!.lunar 33 | year = daYun!.startYear + index 34 | age = daYun!.startAge + index 35 | } 36 | } 37 | 38 | /// 阴历 39 | public var lunar: Lunar? 40 | 41 | public init(daYun: DaYun, index: Int, isGoWith: Bool) { 42 | self.daYun = daYun 43 | self.index = index 44 | self.isGoWith = isGoWith 45 | self.year = daYun.startYear + index 46 | self.age = daYun.startAge + index 47 | self.lunar = daYun.lunar 48 | } 49 | 50 | // XiaoYun(DaYun daYun, int index, bool forward) { 51 | // _daYun = daYun; 52 | // _lunar = daYun.getLunar(); 53 | // _index = index; 54 | // _year = daYun.getStartYear() + index; 55 | // _age = daYun.getStartAge() + index; 56 | // _forward = forward; 57 | // } 58 | // 59 | // int getIndex() => _index; 60 | // 61 | // int getYear() => _year; 62 | // 63 | // int getAge() => _age; 64 | 65 | public func getGanZhi() -> String { 66 | var offset: Int = LunarUtil.getJiaZiIndex(ganZhi: lunar!.getTimeInGanZhi()); 67 | var add: Int = index + 1; 68 | if (daYun!.index > 0) { 69 | add += daYun!.startAge - 1; 70 | } 71 | offset += isGoWith ? add : -add; 72 | let size: Int = LunarUtil.JIA_ZI.count; 73 | while (offset < 0) { 74 | offset += size; 75 | } 76 | offset %= size; 77 | return LunarUtil.JIA_ZI[offset]; 78 | } 79 | 80 | public func getGan() -> String { 81 | let characters = Array(getGanZhi()) 82 | return String(characters[0]) 83 | } 84 | 85 | public func getZhi() -> String { 86 | let characters = Array(getGanZhi()) 87 | return String(characters[1]) 88 | } 89 | 90 | public func getXun() -> String { 91 | return LunarUtil.getXun(ganZhi: getGanZhi()) 92 | } 93 | 94 | public func getXunKong() -> String { 95 | return LunarUtil.getXunKong(ganZhi: getGanZhi()) 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /Sources/SwiftLunar/Timeset/Yun.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Yun.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/19. 6 | // 7 | // 运 8 | 9 | import Foundation 10 | 11 | @available(watchOS 8.0, *) 12 | @available(iOS 15.0, *) 13 | @available(macOS 12.0, *) 14 | public struct Yun: Hashable { 15 | // 性别(1男,0女) 16 | public var gender: Int = 0 17 | 18 | // 起运年数 19 | public var startYear: Int = 0 20 | 21 | // 起运月数 22 | public var startMonth: Int = 0 23 | 24 | // 起运天数 25 | public var startDay: Int = 0 26 | 27 | // 起运小时数 28 | public var startHour: Int = 0 29 | 30 | // 是否顺推 31 | public var isGoWith: Bool = false 32 | 33 | public var genre: Int = 1 34 | 35 | // 阴历 36 | public var lunar: Lunar? { 37 | didSet { 38 | let yang = 0 == (lunar?.getYearGanIndexExact())! % 2 39 | let man = 1 == gender 40 | isGoWith = (yang && man) || (!yang && !man) 41 | computeStart(genre: genre) 42 | } 43 | } 44 | 45 | public init(lunar: Lunar, gender: Int, genre: Int = 1) { 46 | self.lunar = lunar 47 | self.gender = gender 48 | // 阳 49 | let yang: Bool = 0 == lunar.getYearGanIndexExact() % 2 50 | // 男 51 | let man: Bool = 1 == gender 52 | isGoWith = (yang && man) || (!yang && !man) 53 | computeStart(genre: genre) 54 | } 55 | 56 | mutating func computeStart(genre: Int) { 57 | // 上节 58 | let prev: JieQi = lunar!.getPrevJie() 59 | // 下节 60 | let next: JieQi = lunar!.getNextJie() 61 | // 出生日期 62 | let current: Solar = lunar!.solar! 63 | // 阳男阴女顺推,阴男阳女逆推 64 | let start: Solar = isGoWith ? current : prev.solar! 65 | let end: Solar = isGoWith ? next.solar! : current 66 | 67 | var year: Int 68 | var month: Int 69 | var day: Int 70 | var hour: Int = 0 71 | 72 | if (2 == genre) { 73 | var minutes: Int = Calendar(identifier: .gregorian).dateComponents([.minute], from: start.calendar, to: end.calendar).minute! 74 | year = Int(floor(Double(minutes) / 4320)) 75 | minutes -= year * 4320 76 | month = Int(floor(Double(minutes) / 360)) 77 | minutes -= month * 360 78 | day = Int(floor(Double(minutes) / 12)) 79 | minutes -= day * 12 80 | hour = minutes * 2 81 | } else { 82 | let endTimeZhiIndex: Int = (end.hour == 23) 83 | ? 11 84 | : LunarUtil.getTimeZhiIndex(hm: end.toHm()) 85 | let startTimeZhiIndex: Int = (start.hour == 23) 86 | ? 11 87 | : LunarUtil.getTimeZhiIndex(hm: start.toHm()) 88 | // 时辰差 89 | var hourDiff: Int = endTimeZhiIndex - startTimeZhiIndex 90 | // 天数差 91 | var dayDiff: Int = ExactDate.getDaysBetween(ay: start.year, am: start.month, 92 | ad: start.day, by: end.year, bm: end.month, bd: end.day) 93 | if (hourDiff < 0) { 94 | hourDiff += 12 95 | dayDiff -= 1 96 | } 97 | let monthDiff: Int = Int(floor(Double(hourDiff) * 10 / 30)) 98 | month = dayDiff * 4 + monthDiff 99 | day = hourDiff * 10 - monthDiff * 30 100 | year = Int(floor(Double(month) / 12)) 101 | month = month - year * 12 102 | } 103 | startYear = year 104 | startMonth = month 105 | startDay = day 106 | startHour = hour 107 | } 108 | 109 | // int getGender() => _gender 110 | // 111 | // int getStartYear() => _startYear 112 | // 113 | // int getStartMonth() => _startMonth 114 | // 115 | // int getStartDay() => _startDay 116 | // 117 | // int getStartHour() => _startHour 118 | // 119 | // bool isForward() => _forward 120 | 121 | // Lunar getLunar() => _lunar! 122 | 123 | public func getStartSolar() -> Solar { 124 | let birth: Solar = lunar!.solar! 125 | var year: Int = birth.year + startYear 126 | var month: Int = birth.month + startMonth 127 | if (month > 12) { 128 | month -= 12 129 | year += 1 130 | } 131 | var day: Int = birth.day + startDay 132 | var hour: Int = birth.hour + startHour 133 | if (hour > 24) { 134 | day += 1 135 | hour -= 24 136 | } 137 | let days: Int = SolarUtil.getDaysOfMonth(year: year, month: month) 138 | if (day > days) { 139 | day -= days 140 | month += 1 141 | if (month > 12) { 142 | month -= 12 143 | year += 1 144 | } 145 | } 146 | return Solar(fromYmdHms: year, month: month, day: day, hour: hour, minute: birth.minute, second: birth.second) 147 | } 148 | 149 | /// 获取10轮大运 150 | public func getDaYun() -> [DaYun]{ 151 | return getDaYunBy(n: 10) 152 | } 153 | 154 | /// 获取大运 155 | /// [n] 轮数 156 | public func getDaYunBy(n: Int) -> [DaYun]{ 157 | var l: [DaYun] = [] 158 | for i in 0.. String { 407 | return XIU_27[(XIU_OFFSET[abs(month) - 1] + day - 1) % XIU_27.count] 408 | } 409 | } 410 | -------------------------------------------------------------------------------- /Sources/SwiftLunar/Utils/SolarUtil.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SolarUtil.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/11. 6 | // 7 | 8 | import Foundation 9 | 10 | struct SolarUtil { 11 | 12 | static let WEEK: [String] = ["日", "一", "二", "三", "四", "五", "六"] 13 | 14 | static let DAYS_OF_MONTH: [Int] = [ 15 | 31, 16 | 28, 17 | 31, 18 | 30, 19 | 31, 20 | 30, 21 | 31, 22 | 31, 23 | 30, 24 | 31, 25 | 30, 26 | 31 27 | ] 28 | 29 | static let XING_ZUO: [String] = [ 30 | "白羊", 31 | "金牛", 32 | "双子", 33 | "巨蟹", 34 | "狮子", 35 | "处女", 36 | "天秤", 37 | "天蝎", 38 | "射手", 39 | "摩羯", 40 | "水瓶", 41 | "双鱼" 42 | ] 43 | 44 | /// 日期对应的节日 45 | static let FESTIVAL: [String: String] = [ 46 | "1-1": "元旦节", 47 | "2-14": "情人节", 48 | "3-8": "妇女节", 49 | "3-12": "植树节", 50 | "3-15": "消费者权益日", 51 | "4-1": "愚人节", 52 | "5-1": "劳动节", 53 | "5-4": "青年节", 54 | "6-1": "儿童节", 55 | "7-1": "建党节", 56 | "8-1": "建军节", 57 | "9-10": "教师节", 58 | "10-1": "国庆节", 59 | "10-31": "万圣节前夜", 60 | "11-1": "万圣节", 61 | "12-24": "平安夜", 62 | "12-25": "圣诞节" 63 | ] 64 | 65 | /// 几月第几个星期几对应的节日 66 | static let WEEK_FESTIVAL: [String: String] = [ 67 | "3-0-1": "全国中小学生安全教育日", 68 | "5-2-0": "母亲节", 69 | "6-3-0": "父亲节", 70 | "11-4-4": "感恩节" 71 | ] 72 | 73 | /// 日期对应的非正式节日 74 | static let OTHER_FESTIVAL: [String: [String]] = [ 75 | "1-8": ["周恩来逝世纪念日"], 76 | "1-10": ["中国人民警察节", "中国公安110宣传日"], 77 | "1-21": ["列宁逝世纪念日"], 78 | "1-26": ["国际海关日"], 79 | "2-2": ["世界湿地日"], 80 | "2-4": ["世界抗癌日"], 81 | "2-7": ["京汉铁路罢工纪念"], 82 | "2-10": ["国际气象节"], 83 | "2-19": ["邓小平逝世纪念日"], 84 | "2-21": ["国际母语日"], 85 | "2-24": ["第三世界青年日"], 86 | "3-1": ["国际海豹日"], 87 | "3-3": ["全国爱耳日"], 88 | "3-5": ["周恩来诞辰纪念日", "中国青年志愿者服务日"], 89 | "3-6": ["世界青光眼日"], 90 | "3-12": ["孙中山逝世纪念日"], 91 | "3-14": ["马克思逝世纪念日"], 92 | "3-17": ["国际航海日"], 93 | "3-18": ["全国科技人才活动日"], 94 | "3-21": ["世界森林日", "世界睡眠日"], 95 | "3-22": ["世界水日"], 96 | "3-23": ["世界气象日"], 97 | "3-24": ["世界防治结核病日"], 98 | "4-2": ["国际儿童图书日"], 99 | "4-7": ["世界卫生日"], 100 | "4-22": ["列宁诞辰纪念日"], 101 | "4-23": ["世界图书和版权日"], 102 | "4-26": ["世界知识产权日"], 103 | "5-3": ["世界新闻自由日"], 104 | "5-5": ["马克思诞辰纪念日"], 105 | "5-8": ["世界红十字日"], 106 | "5-11": ["世界肥胖日"], 107 | "5-25": ["525心理健康节"], 108 | "5-27": ["上海解放日"], 109 | "5-31": ["世界无烟日"], 110 | "6-5": ["世界环境日"], 111 | "6-6": ["全国爱眼日"], 112 | "6-8": ["世界海洋日"], 113 | "6-11": ["中国人口日"], 114 | "6-14": ["世界献血日"], 115 | "7-1": ["香港回归纪念日"], 116 | "7-7": ["中国人民抗日战争纪念日"], 117 | "7-11": ["世界人口日"], 118 | "8-5": ["恩格斯逝世纪念日"], 119 | "8-6": ["国际电影节"], 120 | "8-12": ["国际青年日"], 121 | "8-22": ["邓小平诞辰纪念日"], 122 | "9-3": ["中国抗日战争胜利纪念日"], 123 | "9-8": ["世界扫盲日"], 124 | "9-9": ["毛泽东逝世纪念日"], 125 | "9-14": ["世界清洁地球日"], 126 | "9-18": ["九一八事变纪念日"], 127 | "9-20": ["全国爱牙日"], 128 | "9-21": ["国际和平日"], 129 | "9-27": ["世界旅游日"], 130 | "10-4": ["世界动物日"], 131 | "10-10": ["辛亥革命纪念日"], 132 | "10-13": ["中国少年先锋队诞辰日"], 133 | "10-25": ["抗美援朝纪念日"], 134 | "11-12": ["孙中山诞辰纪念日"], 135 | "11-17": ["国际大学生节"], 136 | "11-28": ["恩格斯诞辰纪念日"], 137 | "12-1": ["世界艾滋病日"], 138 | "12-12": ["西安事变纪念日"], 139 | "12-13": ["国家公祭日"], 140 | "12-26": ["毛泽东诞辰纪念日"], 141 | ] 142 | 143 | /// 是否闰年 144 | /// @param year 年 145 | /// @return true/false 闰年/非闰年 146 | static func isLeapYear(year: Int)->Bool { 147 | return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0) 148 | } 149 | 150 | /// 获取某年某月有多少天 151 | /// 152 | /// @param year 年 153 | /// @param month 月 154 | /// @return 天数 155 | static func getDaysOfMonth(year: Int, month: Int)->Int { 156 | if (1582 == year && 10 == month) { 157 | return 21; 158 | } 159 | let m: Int = month - 1 160 | var d: Int = DAYS_OF_MONTH[m]; 161 | //公历闰年2月多一天 162 | if (m == 1 && isLeapYear(year: year)) { 163 | d += 1 164 | } 165 | return d 166 | } 167 | 168 | /// 获取某年有多少天(平年365天,闰年366天) 169 | /// 170 | /// @param year 年 171 | /// @return 天数 172 | static func getDaysOfYear(year: Int) -> Int { 173 | return isLeapYear(year: year) ? 366 : 365 174 | } 175 | 176 | /// 获取某天为当年的第几天 177 | /// 178 | /// @param year 年 179 | /// @param month 月 180 | /// @param day 日 181 | /// @return 第几天 182 | static func getDaysInYear(year: Int, month: Int, day: Int) -> Int { 183 | var days: Int = 0; 184 | for i in 1..= 15) { 189 | days -= 10; 190 | } 191 | return days; 192 | } 193 | 194 | /// 获取某年某月有多少周 195 | /// 196 | /// @param year 年 197 | /// @param month 月 198 | /// @param start 星期几作为一周的开始,1234560分别代表星期一至星期天 199 | /// @return 周数 200 | static func getWeeksOfMonth(year: Int, month: Int, start: Int) -> Int { 201 | let days: Int = getDaysOfMonth(year: year, month: month) 202 | var week: Int = Calendar(identifier: .gregorian).component(.weekday, from: ExactDate.fromYmd(year: year, month: month, day: Int(1))) - 1 203 | if (week == -1) { 204 | week = 0; 205 | } 206 | return Int(ceil(Double(days + week - start) * 1.0 / Double(WEEK.count))) 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /Sources/SwiftLunar/Utils/TaoistUtil.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TaoistUtil.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/23. 6 | // 7 | // Taoist tools 8 | struct TaoistUtil { 9 | /// 八会日 10 | static let BA_HUI: [String: String] = [ 11 | "丙午": "天会", 12 | "壬午": "地会", 13 | "壬子": "人会", 14 | "庚午": "日会", 15 | "庚申": "月会", 16 | "辛酉": "星辰会", 17 | "甲辰": "五行会", 18 | "甲戌": "四时会" 19 | ] 20 | 21 | /// 八节日 22 | static let BA_JIE: [String: String] = [ 23 | "立春": "东北方度仙上圣天尊同梵炁始青天君下降", 24 | "春分": "东方玉宝星上天尊同青帝九炁天君下降", 25 | "立夏": "东南方好生度命天尊同梵炁始丹天君下降", 26 | "夏至": "南方玄真万福天尊同赤帝三炁天君下降", 27 | "立秋": "西南方太灵虚皇天尊同梵炁始素天君下降", 28 | "秋分": "西方太妙至极天尊同白帝七炁天君下降", 29 | "立冬": "西北方无量太华天尊同梵炁始玄天君下降", 30 | "冬至": "北方玄上玉宸天尊同黑帝五炁天君下降" 31 | ] 32 | 33 | /// 三会日 34 | static let SAN_HUI: [String] = ["1-7", "7-7", "10-15"]; 35 | 36 | /// 三元日 37 | static let SAN_YUAN: [String] = ["1-15", "7-15", "10-15"]; 38 | 39 | /// 五腊日 40 | static let WU_LA: [String] = ["1-1", "5-5", "7-7", "10-1", "12-8"]; 41 | 42 | /// 暗戊 43 | static let AN_WU: [String] = [ 44 | "未", 45 | "戌", 46 | "辰", 47 | "寅", 48 | "午", 49 | "子", 50 | "酉", 51 | "申", 52 | "巳", 53 | "亥", 54 | "卯", 55 | "丑" 56 | ] 57 | 58 | // The festivals of Taoist 59 | static let FESTIVAL: [String: [TaoistFestival]] = [ 60 | "1-1": [TaoistFestival(name: "天腊之辰", remark: "天腊,此日五帝会于东方九炁青天")], 61 | "1-3": [TaoistFestival(name: "郝真人圣诞"), TaoistFestival(name: "孙真人圣诞")], 62 | "1-5": [TaoistFestival(name: "孙祖清静元君诞")], 63 | "1-7": [TaoistFestival(name: "举迁赏会", remark: "此日上元赐福,天官同地水二官考校罪福")], 64 | "1-9": [TaoistFestival(name: "玉皇上帝圣诞")], 65 | "1-13": [TaoistFestival(name: "关圣帝君飞升")], 66 | "1-15": [TaoistFestival(name: "上元天官圣诞"), TaoistFestival(name: "老祖天师圣诞")], 67 | "1-19": [TaoistFestival(name: "长春邱真人(邱处机)圣诞")], 68 | "1-28": [TaoistFestival(name: "许真君(许逊天师)圣诞")], 69 | "2-1": [TaoistFestival(name: "勾陈天皇大帝圣诞"), TaoistFestival(name: "长春刘真人(刘渊然)圣诞")], 70 | "2-2": [TaoistFestival(name: "土地正神诞"), TaoistFestival(name: "姜太公圣诞")], 71 | "2-3": [TaoistFestival(name: "文昌梓潼帝君圣诞")], 72 | "2-6": [TaoistFestival(name: "东华帝君圣诞")], 73 | "2-13": [TaoistFestival(name: "度人无量葛真君圣诞")], 74 | "2-15": [TaoistFestival(name: "太清道德天尊(太上老君)圣诞")], 75 | "2-19": [TaoistFestival(name: "慈航真人圣诞")], 76 | "3-1": [TaoistFestival(name: "谭祖(谭处端)长真真人圣诞")], 77 | "3-3": [TaoistFestival(name: "玄天上帝圣诞")], 78 | "3-6": [TaoistFestival(name: "眼光娘娘圣诞")], 79 | "3-15": [TaoistFestival(name: "天师张大真人圣诞"), TaoistFestival(name: "财神赵公元帅圣诞")], 80 | "3-16": [TaoistFestival(name: "三茅真君得道之辰"), TaoistFestival(name: "中岳大帝圣诞")], 81 | "3-18": [TaoistFestival(name: "王祖(王处一)玉阳真人圣诞"), TaoistFestival(name: "后土娘娘圣诞")], 82 | "3-19": [TaoistFestival(name: "太阳星君圣诞")], 83 | "3-20": [TaoistFestival(name: "子孙娘娘圣诞")], 84 | "3-23": [TaoistFestival(name: "天后妈祖圣诞")], 85 | "3-26": [TaoistFestival(name: "鬼谷先师诞")], 86 | "3-28": [TaoistFestival(name: "东岳大帝圣诞")], 87 | "4-1": [TaoistFestival(name: "长生谭真君成道之辰")], 88 | "4-10": [TaoistFestival(name: "何仙姑圣诞")], 89 | "4-14": [TaoistFestival(name: "吕祖纯阳祖师圣诞")], 90 | "4-15": [TaoistFestival(name: "钟离祖师圣诞")], 91 | "4-18": [ 92 | TaoistFestival(name: "北极紫微大帝圣诞"), 93 | TaoistFestival(name: "泰山圣母碧霞元君诞"), 94 | TaoistFestival(name: "华佗神医先师诞") 95 | ], 96 | "4-20": [TaoistFestival(name: "眼光圣母娘娘诞")], 97 | "4-28": [TaoistFestival(name: "神农先帝诞")], 98 | "5-1": [TaoistFestival(name: "南极长生大帝圣诞")], 99 | "5-5": [ 100 | TaoistFestival(name: "地腊之辰", remark: "地腊,此日五帝会于南方三炁丹天"), 101 | TaoistFestival(name: "南方雷祖圣诞"), 102 | TaoistFestival(name: "地祗温元帅圣诞"), 103 | TaoistFestival(name: "雷霆邓天君圣诞") 104 | ], 105 | "5-11": [TaoistFestival(name: "城隍爷圣诞")], 106 | "5-13": [TaoistFestival(name: "关圣帝君降神"), TaoistFestival(name: "关平太子圣诞")], 107 | "5-18": [TaoistFestival(name: "张天师圣诞")], 108 | "5-20": [TaoistFestival(name: "马祖丹阳真人圣诞")], 109 | "5-29": [TaoistFestival(name: "紫青白祖师圣诞")], 110 | "6-1": [TaoistFestival(name: "南斗星君下降")], 111 | "6-2": [TaoistFestival(name: "南斗星君下降")], 112 | "6-3": [TaoistFestival(name: "南斗星君下降")], 113 | "6-4": [TaoistFestival(name: "南斗星君下降")], 114 | "6-5": [TaoistFestival(name: "南斗星君下降")], 115 | "6-6": [TaoistFestival(name: "南斗星君下降")], 116 | "6-10": [TaoistFestival(name: "刘海蟾祖师圣诞")], 117 | "6-15": [TaoistFestival(name: "灵官王天君圣诞")], 118 | "6-19": [TaoistFestival(name: "慈航(观音)成道日")], 119 | "6-23": [TaoistFestival(name: "火神圣诞")], 120 | "6-24": [TaoistFestival(name: "南极大帝中方雷祖圣诞"), TaoistFestival(name: "关圣帝君圣诞")], 121 | "6-26": [TaoistFestival(name: "二郎真君圣诞")], 122 | "7-7": [ 123 | TaoistFestival(name: "道德腊之辰", remark: "道德腊,此日五帝会于西方七炁素天"), 124 | TaoistFestival(name: "庆生中会", remark: "此日中元赦罪,地官同天水二官考校罪福") 125 | ], 126 | "7-12": [TaoistFestival(name: "西方雷祖圣诞")], 127 | "7-15": [TaoistFestival(name: "中元地官大帝圣诞")], 128 | "7-18": [TaoistFestival(name: "王母娘娘圣诞")], 129 | "7-20": [TaoistFestival(name: "刘祖(刘处玄)长生真人圣诞")], 130 | "7-22": [TaoistFestival(name: "财帛星君文财神增福相公李诡祖圣诞")], 131 | "7-26": [TaoistFestival(name: "张三丰祖师圣诞")], 132 | "8-1": [TaoistFestival(name: "许真君飞升日")], 133 | "8-3": [TaoistFestival(name: "九天司命灶君诞")], 134 | "8-5": [TaoistFestival(name: "北方雷祖圣诞")], 135 | "8-10": [TaoistFestival(name: "北岳大帝诞辰")], 136 | "8-15": [TaoistFestival(name: "太阴星君诞")], 137 | "9-1": [TaoistFestival(name: "北斗九皇降世之辰")], 138 | "9-2": [TaoistFestival(name: "北斗九皇降世之辰")], 139 | "9-3": [TaoistFestival(name: "北斗九皇降世之辰")], 140 | "9-4": [TaoistFestival(name: "北斗九皇降世之辰")], 141 | "9-5": [TaoistFestival(name: "北斗九皇降世之辰")], 142 | "9-6": [TaoistFestival(name: "北斗九皇降世之辰")], 143 | "9-7": [TaoistFestival(name: "北斗九皇降世之辰")], 144 | "9-8": [TaoistFestival(name: "北斗九皇降世之辰")], 145 | "9-9": [ 146 | TaoistFestival(name: "北斗九皇降世之辰"), 147 | TaoistFestival(name: "斗姥元君圣诞"), 148 | TaoistFestival(name: "重阳帝君圣诞"), 149 | TaoistFestival(name: "玄天上帝飞升"), 150 | TaoistFestival(name: "酆都大帝圣诞") 151 | ], 152 | "9-22": [TaoistFestival(name: "增福财神诞")], 153 | "9-23": [TaoistFestival(name: "萨翁真君圣诞")], 154 | "9-28": [TaoistFestival(name: "五显灵官马元帅圣诞")], 155 | "10-1": [ 156 | TaoistFestival(name: "民岁腊之辰", remark: "民岁腊,此日五帝会于北方五炁黑天"), 157 | TaoistFestival(name: "东皇大帝圣诞") 158 | ], 159 | "10-3": [TaoistFestival(name: "三茅应化真君圣诞")], 160 | "10-6": [TaoistFestival(name: "天曹诸司五岳五帝圣诞")], 161 | "10-15": [ 162 | TaoistFestival(name: "下元水官大帝圣诞"), 163 | TaoistFestival(name: "建生大会", remark: "此日下元解厄,水官同天地二官考校罪福") 164 | ], 165 | "10-18": [TaoistFestival(name: "地母娘娘圣诞")], 166 | "10-19": [TaoistFestival(name: "长春邱真君飞升")], 167 | "10-20": [TaoistFestival(name: "虚靖天师(即三十代天师弘悟张真人)诞")], 168 | "11-6": [TaoistFestival(name: "西岳大帝圣诞")], 169 | "11-9": [TaoistFestival(name: "湘子韩祖圣诞")], 170 | "11-11": [TaoistFestival(name: "太乙救苦天尊圣诞")], 171 | "11-26": [TaoistFestival(name: "北方五道圣诞")], 172 | "12-8": [TaoistFestival(name: "王侯腊之辰", remark: "王侯腊,此日五帝会于上方玄都玉京")], 173 | "12-16": [TaoistFestival(name: "南岳大帝圣诞"), TaoistFestival(name: "福德正神诞")], 174 | "12-20": [TaoistFestival(name: "鲁班先师圣诞")], 175 | "12-21": [TaoistFestival(name: "天猷上帝圣诞")], 176 | "12-22": [TaoistFestival(name: "重阳祖师圣诞")], 177 | "12-23": [TaoistFestival(name: "祭灶王", remark: "最适宜谢旧年太岁,开启拜新年太岁")], 178 | "12-25": [TaoistFestival(name: "玉帝巡天"), TaoistFestival(name: "天神下降")], 179 | "12-29": [TaoistFestival(name: "清静孙真君(孙不二)成道")] 180 | ] 181 | } 182 | -------------------------------------------------------------------------------- /Tests/SwiftLunarTests/BrassMonkeysTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BrassMonkeysTests.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/22. 6 | // 7 | import XCTest 8 | @testable import SwiftLunar 9 | 10 | @available(macOS 12.0, *) 11 | final class SBrassMonkeysTests: XCTestCase { 12 | func testBrassMonkeys1() throws { 13 | let solar: Solar = Solar(fromYmd: 2020, month: 12, day: 21) 14 | let lunar: Lunar = solar.getLunar() 15 | let brassMonkeys: BrassMonkeys? = lunar.getBrassMonkeys() 16 | XCTAssertEqual(brassMonkeys!.toString(), "一九") 17 | XCTAssertEqual(brassMonkeys!.toFullString(), "一九第1天") 18 | } 19 | 20 | func testBrassMonkeys2() throws { 21 | let solar: Solar = Solar(fromYmd: 2020, month: 12, day: 22) 22 | let lunar: Lunar = solar.getLunar() 23 | let brassMonkeys: BrassMonkeys? = lunar.getBrassMonkeys() 24 | XCTAssertEqual(brassMonkeys!.toString(), "一九") 25 | XCTAssertEqual(brassMonkeys!.toFullString(), "一九第2天") 26 | } 27 | 28 | func testBrassMonkeys3() throws { 29 | let solar: Solar = Solar(fromYmd: 2020, month: 1, day: 7) 30 | let lunar: Lunar = solar.getLunar() 31 | let brassMonkeys: BrassMonkeys? = lunar.getBrassMonkeys() 32 | XCTAssertEqual(brassMonkeys!.toString(), "二九") 33 | XCTAssertEqual(brassMonkeys!.toFullString(), "二九第8天") 34 | } 35 | 36 | func testBrassMonkeys4() throws { 37 | let solar: Solar = Solar(fromYmd: 2021, month: 1, day: 6) 38 | let lunar: Lunar = solar.getLunar() 39 | let brassMonkeys: BrassMonkeys? = lunar.getBrassMonkeys() 40 | XCTAssertEqual(brassMonkeys!.toString(), "二九") 41 | XCTAssertEqual(brassMonkeys!.toFullString(), "二九第8天") 42 | } 43 | 44 | func testBrassMonkeys5() throws { 45 | let solar: Solar = Solar(fromYmd: 2021, month: 1, day: 8) 46 | let lunar: Lunar = solar.getLunar() 47 | let brassMonkeys: BrassMonkeys? = lunar.getBrassMonkeys() 48 | XCTAssertEqual(brassMonkeys!.toString(), "三九") 49 | XCTAssertEqual(brassMonkeys!.toFullString(), "三九第1天") 50 | } 51 | 52 | func testBrassMonkeys6() throws { 53 | let solar: Solar = Solar(fromYmd: 2021, month: 3, day: 5) 54 | let lunar: Lunar = solar.getLunar() 55 | let brassMonkeys: BrassMonkeys? = lunar.getBrassMonkeys() 56 | XCTAssertEqual(brassMonkeys!.toString(), "九九") 57 | XCTAssertEqual(brassMonkeys!.toFullString(), "九九第3天") 58 | } 59 | 60 | func testBrassMonkeys7() throws { 61 | let solar: Solar = Solar(fromYmd: 2021, month: 7, day: 5) 62 | let lunar: Lunar = solar.getLunar() 63 | let brassMonkeys: BrassMonkeys? = lunar.getBrassMonkeys() 64 | XCTAssertNil(brassMonkeys) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Tests/SwiftLunarTests/BuddhisTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BuddhisTests.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/21. 6 | // 7 | import XCTest 8 | @testable import SwiftLunar 9 | 10 | @available(macOS 12.0, *) 11 | final class BuddhisTests: XCTestCase { 12 | func testBuddhis1() throws { 13 | let buddhis: Buddhis = Buddhis(lunar: Lunar(fromYmdHms: 2021, lunarMonth: 10, lunarDay: 14)) 14 | XCTAssertEqual(buddhis.toFullString(), "二五六五年十月十四 (三元降) (四天王巡行)") 15 | } 16 | 17 | func testBuddhis2() throws { 18 | let buddhis: Buddhis = Buddhis(lunar: Lunar(fromYmdHms: 2020, lunarMonth: 4, lunarDay: 13)) 19 | XCTAssertEqual(buddhis.xiu, "氐") 20 | XCTAssertEqual(buddhis.zheng, "土") 21 | XCTAssertEqual(buddhis.animal, "貉") 22 | XCTAssertEqual(buddhis.gong, "东") 23 | XCTAssertEqual(buddhis.shou, "青龙") 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Tests/SwiftLunarTests/ConstellationTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ConstellationTests.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/23. 6 | // 7 | import XCTest 8 | @testable import SwiftLunar 9 | 10 | @available(macOS 12.0, *) 11 | final class ConstellationTests: XCTestCase { 12 | 13 | func testConstellation1() throws { 14 | let solar: Solar = Solar(fromYmd: 2020, month: 3, day: 21) 15 | XCTAssertEqual(solar.constellation, "白羊") 16 | } 17 | 18 | func testConstellation2() throws { 19 | let solar: Solar = Solar(fromYmd: 2020, month: 4, day: 19) 20 | XCTAssertEqual(solar.constellation, "白羊") 21 | } 22 | 23 | func testConstellation3() throws { 24 | let solar: Solar = Solar(fromYmd: 2020, month: 4, day: 20) 25 | XCTAssertEqual(solar.constellation, "金牛") 26 | } 27 | 28 | func testConstellation4() throws { 29 | let solar: Solar = Solar(fromYmd: 2020, month: 5, day: 20) 30 | XCTAssertEqual(solar.constellation, "金牛") 31 | } 32 | 33 | func testConstellation5() throws { 34 | let solar: Solar = Solar(fromYmd: 2020, month: 5, day: 21) 35 | XCTAssertEqual(solar.constellation, "双子") 36 | } 37 | 38 | func testConstellation6() throws { 39 | let solar: Solar = Solar(fromYmd: 2020, month: 6, day: 21) 40 | XCTAssertEqual(solar.constellation, "双子") 41 | } 42 | 43 | func testConstellation7() throws { 44 | let solar: Solar = Solar(fromYmd: 2020, month: 6, day: 22) 45 | XCTAssertEqual(solar.constellation, "巨蟹") 46 | } 47 | 48 | func testConstellation8() throws { 49 | let solar: Solar = Solar(fromYmd: 2020, month: 7, day: 22) 50 | XCTAssertEqual(solar.constellation, "巨蟹") 51 | } 52 | 53 | func testConstellation9() throws { 54 | let solar: Solar = Solar(fromYmd: 2020, month: 7, day: 23) 55 | XCTAssertEqual(solar.constellation, "狮子") 56 | } 57 | 58 | func testConstellation10() throws { 59 | let solar: Solar = Solar(fromYmd: 2020, month: 8, day: 22) 60 | XCTAssertEqual(solar.constellation, "狮子") 61 | } 62 | 63 | func testConstellation11() throws { 64 | let solar: Solar = Solar(fromYmd: 2020, month: 8, day: 23) 65 | XCTAssertEqual(solar.constellation, "处女") 66 | } 67 | 68 | func testConstellation12() throws { 69 | let solar: Solar = Solar(fromYmd: 2020, month: 9, day: 22) 70 | XCTAssertEqual(solar.constellation, "处女") 71 | } 72 | 73 | func testConstellation13() throws { 74 | let solar: Solar = Solar(fromYmd: 2020, month: 9, day: 23) 75 | XCTAssertEqual(solar.constellation, "天秤") 76 | } 77 | 78 | func testConstellation14() throws { 79 | let solar: Solar = Solar(fromYmd: 2020, month: 10, day: 23) 80 | XCTAssertEqual(solar.constellation, "天秤") 81 | } 82 | 83 | func testConstellation15() throws { 84 | let solar: Solar = Solar(fromYmd: 2020, month: 10, day: 24) 85 | XCTAssertEqual(solar.constellation, "天蝎") 86 | } 87 | 88 | func testConstellation16() throws { 89 | let solar: Solar = Solar(fromYmd: 2020, month: 11, day: 22) 90 | XCTAssertEqual(solar.constellation, "天蝎") 91 | } 92 | 93 | func testConstellation17() throws { 94 | let solar: Solar = Solar(fromYmd: 2020, month: 11, day: 23) 95 | XCTAssertEqual(solar.constellation, "射手") 96 | } 97 | 98 | func testConstellation18() throws { 99 | let solar: Solar = Solar(fromYmd: 2020, month: 12, day: 21) 100 | XCTAssertEqual(solar.constellation, "射手") 101 | } 102 | 103 | func testConstellation19() throws { 104 | let solar: Solar = Solar(fromYmd: 2020, month: 12, day: 22) 105 | XCTAssertEqual(solar.constellation, "摩羯") 106 | } 107 | 108 | func testConstellation20() throws { 109 | let solar: Solar = Solar(fromYmd: 2021, month: 1, day: 19) 110 | XCTAssertEqual(solar.constellation, "摩羯") 111 | } 112 | 113 | func testConstellation21() throws { 114 | let solar: Solar = Solar(fromYmd: 2021, month: 1, day: 20) 115 | XCTAssertEqual(solar.constellation, "水瓶") 116 | } 117 | 118 | func testConstellation22() throws { 119 | let solar: Solar = Solar(fromYmd: 2021, month: 2, day: 18) 120 | XCTAssertEqual(solar.constellation, "水瓶") 121 | } 122 | 123 | func testConstellation23() throws { 124 | let solar: Solar = Solar(fromYmd: 2021, month: 2, day: 19) 125 | XCTAssertEqual(solar.constellation, "双鱼") 126 | } 127 | 128 | func testConstellation24() throws { 129 | let solar: Solar = Solar(fromYmd: 2021, month: 3, day: 20) 130 | XCTAssertEqual(solar.constellation, "双鱼") 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /Tests/SwiftLunarTests/CycleVoid.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CycleVoid.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/22. 6 | // 7 | import XCTest 8 | @testable import SwiftLunar 9 | 10 | @available(macOS 12.0, *) 11 | final class CycleVoidTests: XCTestCase { 12 | func testCycleVoid1() throws { 13 | let solar: Solar = Solar(fromYmdHms: 2020, month: 11, day: 19, hour: 0, minute: 0, second: 0) 14 | let lunar: Lunar = solar.getLunar() 15 | XCTAssertEqual(lunar.getYearXun(), "甲午") 16 | } 17 | 18 | func testCycleVoid2() throws { 19 | let solar: Solar = Solar(fromYmdHms: 2020, month: 11, day: 19, hour: 0, minute: 0, second: 0) 20 | let lunar: Lunar = solar.getLunar() 21 | XCTAssertEqual(lunar.getYearXunKong(), "辰巳") 22 | XCTAssertEqual(lunar.getMonthXunKong(), "午未") 23 | XCTAssertEqual(lunar.getDayXunKong(), "戌亥") 24 | } 25 | 26 | func testCycleVoid3() throws { 27 | let solar: Solar = Solar(fromYmdHms: 1990, month: 12, day: 23, hour: 8, minute: 37, second: 0) 28 | let lunar: Lunar = solar.getLunar() 29 | let timeset: Timeset = lunar.getTimeset() 30 | XCTAssertEqual(timeset.getDayXunKong(), "子丑") 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Tests/SwiftLunarTests/DateTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Date_test.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/13. 6 | // 7 | import XCTest 8 | 9 | @available(macOS 12.0, *) 10 | final class DateTests: XCTestCase { 11 | func testDate() throws { 12 | let dateFormatter = DateFormatter() 13 | dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS" 14 | let date: Date = dateFormatter.date(from: "0320-02-03 08:00:00.000")! 15 | XCTAssertEqual(date.formatted(.dateTime.year()), "320") 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /Tests/SwiftLunarTests/DogDaysTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/21. 6 | // 7 | import XCTest 8 | @testable import SwiftLunar 9 | 10 | @available(macOS 12.0, *) 11 | final class DogDaysTests: XCTestCase { 12 | func testDogDays1() throws { 13 | let solar: Solar = Solar(fromYmd: 2011, month: 7, day: 14) 14 | let lunar: Lunar = solar.getLunar() 15 | let dogDays: DogDays? = lunar.getDogDays() 16 | XCTAssertEqual(dogDays!.toString(), "初伏") 17 | XCTAssertEqual(dogDays!.toFullString(), "初伏第1天") 18 | } 19 | 20 | func testDogDays2() throws { 21 | let solar: Solar = Solar(fromYmd: 2011, month: 7, day: 23) 22 | let lunar: Lunar = solar.getLunar() 23 | let dogDays: DogDays? = lunar.getDogDays() 24 | XCTAssertEqual(dogDays!.toString(), "初伏") 25 | XCTAssertEqual(dogDays!.toFullString(), "初伏第10天") 26 | } 27 | 28 | func testDogDays3() throws { 29 | let solar: Solar = Solar(fromYmd: 2011, month: 7, day: 24) 30 | let lunar: Lunar = solar.getLunar() 31 | let dogDays: DogDays? = lunar.getDogDays() 32 | XCTAssertEqual(dogDays!.toString(), "中伏") 33 | XCTAssertEqual(dogDays!.toFullString(), "中伏第1天") 34 | } 35 | 36 | func testDogDays4() throws { 37 | let solar: Solar = Solar(fromYmd: 2011, month: 8, day: 12) 38 | let lunar: Lunar = solar.getLunar() 39 | let dogDays: DogDays? = lunar.getDogDays() 40 | XCTAssertEqual(dogDays!.toString(), "中伏") 41 | XCTAssertEqual(dogDays!.toFullString(), "中伏第20天") 42 | } 43 | 44 | func testDogDays5() throws { 45 | let solar: Solar = Solar(fromYmd: 2011, month: 8, day: 13) 46 | let lunar: Lunar = solar.getLunar() 47 | let dogDays: DogDays? = lunar.getDogDays() 48 | XCTAssertEqual(dogDays!.toString(), "末伏") 49 | XCTAssertEqual(dogDays!.toFullString(), "末伏第1天") 50 | } 51 | 52 | func testDogDays6() throws { 53 | let solar: Solar = Solar(fromYmd: 2011, month: 8, day: 22) 54 | let lunar: Lunar = solar.getLunar() 55 | let dogDays: DogDays? = lunar.getDogDays() 56 | XCTAssertEqual(dogDays!.toString(), "末伏") 57 | XCTAssertEqual(dogDays!.toFullString(), "末伏第10天") 58 | } 59 | 60 | func testDogDays7() throws { 61 | let solar: Solar = Solar(fromYmd: 2011, month: 7, day: 13) 62 | let lunar: Lunar = solar.getLunar() 63 | let dogDays: DogDays? = lunar.getDogDays() 64 | XCTAssertNil(dogDays) 65 | } 66 | 67 | func testDogDays8() throws { 68 | let solar: Solar = Solar(fromYmd: 2011, month: 8, day: 23) 69 | let lunar: Lunar = solar.getLunar() 70 | let dogDays: DogDays? = lunar.getDogDays() 71 | XCTAssertNil(dogDays) 72 | } 73 | 74 | func testDogDays9() throws { 75 | let solar: Solar = Solar(fromYmd: 2012, month: 7, day: 18) 76 | let lunar: Lunar = solar.getLunar() 77 | let dogDays: DogDays? = lunar.getDogDays() 78 | XCTAssertEqual(dogDays!.toString(), "初伏") 79 | XCTAssertEqual(dogDays!.toFullString(), "初伏第1天") 80 | } 81 | 82 | func testDogDays10() throws { 83 | let solar: Solar = Solar(fromYmd: 2012, month: 8, day: 5) 84 | let lunar: Lunar = solar.getLunar() 85 | let dogDays: DogDays? = lunar.getDogDays() 86 | XCTAssertEqual(dogDays!.toString(), "中伏") 87 | XCTAssertEqual(dogDays!.toFullString(), "中伏第9天") 88 | } 89 | 90 | func testDogDays11() throws { 91 | let solar: Solar = Solar(fromYmd: 2012, month: 8, day: 8) 92 | let lunar: Lunar = solar.getLunar() 93 | let dogDays: DogDays? = lunar.getDogDays() 94 | XCTAssertEqual(dogDays!.toString(), "末伏") 95 | XCTAssertEqual(dogDays!.toFullString(), "末伏第2天") 96 | } 97 | 98 | func testDogDays12() throws { 99 | let solar: Solar = Solar(fromYmd: 2020, month: 7, day: 17) 100 | let lunar: Lunar = solar.getLunar() 101 | let dogDays: DogDays? = lunar.getDogDays() 102 | XCTAssertEqual(dogDays!.toString(), "初伏") 103 | XCTAssertEqual(dogDays!.toFullString(), "初伏第2天") 104 | } 105 | 106 | func testDogDays13() throws { 107 | let solar: Solar = Solar(fromYmd: 2020, month: 7, day: 26) 108 | let lunar: Lunar = solar.getLunar() 109 | let dogDays: DogDays? = lunar.getDogDays() 110 | XCTAssertEqual(dogDays!.toString(), "中伏") 111 | XCTAssertEqual(dogDays!.toFullString(), "中伏第1天") 112 | } 113 | 114 | func testDogDays14() throws { 115 | let solar: Solar = Solar(fromYmd: 2020, month: 8, day: 24) 116 | let lunar: Lunar = solar.getLunar() 117 | let dogDays: DogDays? = lunar.getDogDays() 118 | XCTAssertEqual(dogDays!.toString(), "末伏") 119 | XCTAssertEqual(dogDays!.toFullString(), "末伏第10天") 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /Tests/SwiftLunarTests/FestivalTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Festival_test.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/18. 6 | // 7 | 8 | import XCTest 9 | @testable import SwiftLunar 10 | 11 | @available(macOS 12.0, *) 12 | final class FestivalTests: XCTestCase { 13 | func testFestival() throws { 14 | let solar1: Solar = Solar(fromYmd: 2020, month: 11, day: 26) 15 | XCTAssertEqual(solar1.festivals.description, "[\"感恩节\"]") 16 | 17 | let solar2: Solar = Solar(fromYmd: 2020, month: 6, day: 21) 18 | XCTAssertEqual(solar2.festivals.description, "[\"父亲节\"]") 19 | 20 | let solar3: Solar = Solar(fromYmd: 2021, month: 5, day: 9) 21 | XCTAssertEqual(solar3.festivals.description, "[\"母亲节\"]") 22 | 23 | let solar4: Solar = Solar(fromYmd: 1986, month: 11, day: 27) 24 | XCTAssertEqual(solar4.festivals.description, "[\"感恩节\"]") 25 | 26 | let solar5: Solar = Solar(fromYmd: 1985, month: 6, day: 16) 27 | XCTAssertEqual(solar5.festivals.description, "[\"父亲节\"]") 28 | 29 | let solar6: Solar = Solar(fromYmd: 1984, month: 5, day: 13) 30 | XCTAssertEqual(solar6.festivals.description, "[\"母亲节\"]") 31 | 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /Tests/SwiftLunarTests/HalfYearTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HalfYearTests.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/19. 6 | // 7 | 8 | import XCTest 9 | @testable import SwiftLunar 10 | 11 | @available(macOS 12.0, *) 12 | final class HalfYearTests: XCTestCase { 13 | func testHalfYearForFirst() throws { 14 | 15 | let halfYear: SolarHalfYear = SolarHalfYear(year: 2019, month: 5) 16 | XCTAssertEqual(halfYear.toString(), "2019.1") 17 | XCTAssertEqual(halfYear.toFullString(), "2019年上半年") 18 | } 19 | 20 | func testHalfYearForSecond() throws { 21 | 22 | let halfYear: SolarHalfYear = SolarHalfYear(year: 2019, month: 5).next(halfYears: 1) 23 | XCTAssertEqual(halfYear.toString(), "2019.2") 24 | XCTAssertEqual(halfYear.toFullString(), "2019年下半年") 25 | } 26 | 27 | func testHalfYearForThird() throws { 28 | 29 | let halfYear: SolarHalfYear = SolarHalfYear(year: 2019, month: 5).next(halfYears: -1) 30 | XCTAssertEqual(halfYear.toString(), "2018.2") 31 | XCTAssertEqual(halfYear.toFullString(), "2018年下半年") 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Tests/SwiftLunarTests/HolidayTestst.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Holiday_test.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/18. 6 | // 7 | 8 | import XCTest 9 | @testable import SwiftLunar 10 | 11 | @available(macOS 12.0, *) 12 | final class HolidayTests: XCTestCase { 13 | @available(macOS 13.0, *) 14 | func testHoliday() throws { 15 | let holiday: Holiday? = HolidayUtil.getHoliday(ymd: "2010-01-01") 16 | // let solar1: Solar = Solar(fromYmd: 2020, month: 11, day: 26) 17 | XCTAssertEqual(holiday!.name, "元旦节") 18 | 19 | // HolidayUtil.fix 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Tests/SwiftLunarTests/JulianDayTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JulianDayTests.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/18. 6 | // 7 | 8 | import XCTest 9 | @testable import SwiftLunar 10 | 11 | @available(macOS 12.0, *) 12 | final class JulianDayTests: XCTestCase { 13 | func testJulianDay() throws { 14 | let solar11: Solar = Solar(fromYmd: 2020, month: 7, day: 15) 15 | XCTAssertEqual(solar11.julianDay, 2459045.5) 16 | 17 | let solar12: Solar = Solar(fromJulianDay: 2459045.5) 18 | XCTAssertEqual(solar12.toYmdHms(), "2020-07-15 00:00:00") 19 | 20 | let solar21: Solar = Solar(fromYmdHms: 9999, month: 12, day: 30, hour: 12, minute: 0, second: 0) 21 | XCTAssertEqual(solar21.julianDay, 5373483.0) 22 | 23 | let solar22: Solar = Solar(fromJulianDay: 5373483.0) 24 | XCTAssertEqual(solar22.toYmdHms(), "9999-12-30 12:00:00") 25 | 26 | let solar31: Solar = Solar(fromYmdHms: 1905, month: 2, day: 4, hour: 12, minute: 0, second: 0) 27 | XCTAssertEqual(solar31.julianDay, 2416881.0) 28 | 29 | let solar32: Solar = Solar(fromJulianDay: 2416881.0) 30 | XCTAssertEqual(solar32.toYmdHms(), "1905-02-04 12:00:00") 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /Tests/SwiftLunarTests/LiuYaoTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LiuYaoTests.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/22. 6 | // 7 | import XCTest 8 | @testable import SwiftLunar 9 | 10 | @available(macOS 12.0, *) 11 | final class LiuYaoTests: XCTestCase { 12 | func testLiuYao1() throws { 13 | let solar: Solar = Solar(fromYmd: 2020, month: 4, day: 23) 14 | let lunar: Lunar = solar.getLunar() 15 | XCTAssertEqual(lunar.getLiuYao(), "佛灭") 16 | } 17 | 18 | func testLiuYao2() throws { 19 | let solar: Solar = Solar(fromYmd: 2021, month: 1, day: 15) 20 | let lunar: Lunar = solar.getLunar() 21 | XCTAssertEqual(lunar.getLiuYao(), "友引") 22 | } 23 | 24 | func testLiuYao3() throws { 25 | let solar: Solar = Solar(fromYmd: 2017, month: 1, day: 5) 26 | let lunar: Lunar = solar.getLunar() 27 | XCTAssertEqual(lunar.getLiuYao(), "先胜") 28 | } 29 | 30 | func testLiuYao4() throws { 31 | let solar: Solar = Solar(fromYmd: 2020, month: 4, day: 10) 32 | let lunar: Lunar = solar.getLunar() 33 | XCTAssertEqual(lunar.getLiuYao(), "友引") 34 | } 35 | 36 | func testLiuYao5() throws { 37 | let solar: Solar = Solar(fromYmd: 2020, month: 6, day: 11) 38 | let lunar: Lunar = solar.getLunar() 39 | XCTAssertEqual(lunar.getLiuYao(), "大安") 40 | } 41 | 42 | func testLiuYao6() throws { 43 | let solar: Solar = Solar(fromYmd: 2020, month: 6, day: 1) 44 | let lunar: Lunar = solar.getLunar() 45 | XCTAssertEqual(lunar.getLiuYao(), "先胜") 46 | } 47 | 48 | func testLiuYao7() throws { 49 | let solar: Solar = Solar(fromYmd: 2020, month: 12, day: 8) 50 | let lunar: Lunar = solar.getLunar() 51 | XCTAssertEqual(lunar.getLiuYao(), "先负") 52 | } 53 | 54 | func testLiuYao8() throws { 55 | let solar: Solar = Solar(fromYmd: 2020, month: 12, day: 11) 56 | let lunar: Lunar = solar.getLunar() 57 | XCTAssertEqual(lunar.getLiuYao(), "赤口") 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Tests/SwiftLunarTests/LunarTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import SwiftLunar 3 | 4 | @available(macOS 12.0, *) 5 | final class LunarTests: XCTestCase { 6 | func testLunar() throws { 7 | let lunar: Lunar = Lunar(fromYmdHms: 2019, lunarMonth: 3, lunarDay: 27, hour: 0, minute: 0, second: 0) 8 | XCTAssertEqual(lunar.toString(), "二〇一九年三月廿七") 9 | XCTAssertEqual(lunar.toFullString(), "二〇一九年三月廿七 己亥(猪)年 戊辰(龙)月 戊戌(狗)日 子(鼠)时 纳音[平地木 大林木 平地木 桑柘木] 星期三 西方白虎 星宿[参水猿](吉) 彭祖百忌[戊不受田田主不祥 戌不吃犬作怪上床] 喜神方位[巽](东南) 阳贵神方位[艮](东北) 阴贵神方位[坤](西南) 福神方位[艮](东北) 财神方位[坎](正北) 冲[(壬辰)龙] 煞[北]") 10 | XCTAssertEqual(lunar.solar?.toString(), "2019-05-01") 11 | XCTAssertEqual(lunar.solar?.toFullString(), "2019-05-01 00:00:00 星期三 (劳动节) 金牛座") 12 | } 13 | func testLunar1() throws { 14 | let solar: Solar = Solar(fromYmdHms: 1, month: 1, day: 1, hour: 12, minute: 0, second: 0) 15 | XCTAssertEqual(solar.getLunar().toString(), "〇年冬月十八") 16 | } 17 | func testLunar2() throws { 18 | let solar: Solar = Solar(fromYmdHms: 9999, month: 12, day: 31, hour: 12, minute: 0, second: 0) 19 | XCTAssertEqual(solar.getLunar().toString(), "九九九九年腊月初二") 20 | } 21 | func testLunar3() throws { 22 | let lunar: Lunar = Lunar(fromYmdHms: 0, lunarMonth: 11, lunarDay: 18, hour: 12, minute: 0, second: 0) 23 | XCTAssertEqual(lunar.solar!.toString(), "0001-01-01") 24 | } 25 | func testLunar4() throws { 26 | let lunar: Lunar = Lunar(fromYmdHms: 9999, lunarMonth: 12, lunarDay: 2, hour: 12, minute: 0, second: 0) 27 | XCTAssertEqual(lunar.solar!.toString(), "9999-12-31") 28 | } 29 | func testLunar5() throws { 30 | let lunar: Lunar = Lunar(fromYmdHms: 1905, lunarMonth: 1, lunarDay: 1, hour: 12, minute: 0, second: 0) 31 | XCTAssertEqual(lunar.solar!.toString(), "1905-02-04") 32 | } 33 | func testLunar6() throws { 34 | let lunar: Lunar = Lunar(fromYmdHms: 2038, lunarMonth: 12, lunarDay: 29, hour: 12, minute: 0, second: 0) 35 | XCTAssertEqual(lunar.solar!.toString(), "2039-01-23") 36 | } 37 | func testLunar7() throws { 38 | let lunar: Lunar = Lunar(fromYmdHms: 2020, lunarMonth: -4, lunarDay: 2, hour: 13, minute: 0, second: 0) 39 | XCTAssertEqual(lunar.toString(), "二〇二〇年闰四月初二") 40 | XCTAssertEqual(lunar.solar!.toString(), "2020-05-24") 41 | } 42 | func testLunar8() throws { 43 | let lunar: Lunar = Lunar(fromYmdHms: 2020, lunarMonth: 12, lunarDay: 10, hour: 13, minute: 0, second: 0) 44 | XCTAssertEqual(lunar.toString(), "二〇二〇年腊月初十") 45 | XCTAssertEqual(lunar.solar!.toString(), "2021-01-22") 46 | } 47 | func testLunar9() throws { 48 | let lunar: Lunar = Lunar(fromYmdHms: 1500, lunarMonth: 1, lunarDay: 1, hour: 12, minute: 0, second: 0) 49 | XCTAssertEqual(lunar.solar!.toString(), "1500-01-31") 50 | } 51 | func testLunar10() throws { 52 | let lunar: Lunar = Lunar(fromYmdHms: 1500, lunarMonth: 12, lunarDay: 29, hour: 12, minute: 0, second: 0) 53 | XCTAssertEqual(lunar.solar!.toString(), "1501-01-18") 54 | } 55 | func testLunar11() throws { 56 | let solar: Solar = Solar(fromYmdHms: 1500, month: 1, day: 1, hour: 12, minute: 0, second: 0) 57 | XCTAssertEqual(solar.getLunar().toString(), "一四九九年腊月初一") 58 | } 59 | func testLunar12() throws { 60 | let solar: Solar = Solar(fromYmdHms: 1500, month: 12, day: 31, hour: 12, minute: 0, second: 0) 61 | XCTAssertEqual(solar.getLunar().toString(), "一五〇〇年腊月十一") 62 | } 63 | func testLunar13() throws { 64 | let solar: Solar = Solar(fromYmdHms: 1582, month: 10, day: 4, hour: 12, minute: 0, second: 0) 65 | XCTAssertEqual(solar.getLunar().toString(), "一五八二年九月十八") 66 | } 67 | func testLunar14() throws { 68 | let solar: Solar = Solar(fromYmdHms: 1582, month: 10, day: 15, hour: 12, minute: 0, second: 0) 69 | XCTAssertEqual(solar.getLunar().toString(), "一五八二年九月十九") 70 | } 71 | func testLunar15() throws { 72 | let lunar: Lunar = Lunar(fromYmdHms: 1582, lunarMonth: 9, lunarDay: 18, hour: 12, minute: 0, second: 0) 73 | XCTAssertEqual(lunar.solar!.toString(), "1582-10-04") 74 | } 75 | func testLunar16() throws { 76 | let lunar: Lunar = Lunar(fromYmdHms: 1582, lunarMonth: 9, lunarDay: 19, hour: 12, minute: 0, second: 0) 77 | XCTAssertEqual(lunar.solar!.toString(), "1582-10-15") 78 | } 79 | func testLunar17() throws { 80 | let lunar: Lunar = Lunar(fromYmdHms: 2019, lunarMonth: 12, lunarDay: 12, hour: 11, minute: 22, second: 0) 81 | XCTAssertEqual(lunar.solar!.toString(), "2020-01-06") 82 | } 83 | func testLunar18() throws { 84 | let lunar: Lunar = Lunar(fromYmdHms: 2021, lunarMonth: 12, lunarDay: 29) 85 | XCTAssertEqual(lunar.getFestivals()[0], "除夕") 86 | } 87 | func testLunar19() throws { 88 | let lunar: Lunar = Lunar(fromYmdHms: 2020, lunarMonth: 12, lunarDay: 30) 89 | XCTAssertEqual(lunar.getFestivals()[0], "除夕") 90 | } 91 | func testLunar20() throws { 92 | let lunar: Lunar = Lunar(fromYmdHms: 2020, lunarMonth: 12, lunarDay: 29) 93 | XCTAssertEqual(lunar.getFestivals().count, 0) 94 | } 95 | func testLunar21() throws { 96 | let solar: Solar = Solar(fromYmd:2022, month:1, day:31) 97 | let lunar = solar.getLunar() 98 | XCTAssertEqual(lunar.getFestivals()[0], "除夕") 99 | } 100 | func testLunar22() throws { 101 | let lunar: Lunar = Lunar(fromYmdHms: 2033, lunarMonth: -11, lunarDay: 1) 102 | XCTAssertEqual(lunar.getSolar().toYmd(), "2033-12-22") 103 | } 104 | func testLunar23() throws { 105 | let lunar: Lunar = Lunar(fromYmdHms: 2022, lunarMonth: 1, lunarDay: 1) 106 | XCTAssertEqual(lunar.getYearNineStar().toString(), "六白金开阳") 107 | } 108 | func testLunar24() throws { 109 | let lunar: Lunar = Lunar(fromYmdHms: 2033, lunarMonth: 1, lunarDay: 1) 110 | XCTAssertEqual(lunar.getYearNineStar().toString(), "四绿木天权") 111 | } 112 | func testLunar25() throws { 113 | let solar: Solar = Solar(fromYmdHms: 2021, month: 6, day: 7, hour: 21, minute: 18, second: 0) 114 | let lunar: Lunar = solar.getLunar() 115 | XCTAssertEqual(lunar.toString(), "二〇二一年四月廿七") 116 | } 117 | func testLunar26() throws { 118 | let lunar: Lunar = Lunar(fromYmdHms: 2021, lunarMonth: 6, lunarDay: 7, hour: 21, minute: 18, second: 0) 119 | let solar: Solar = lunar.getSolar() 120 | XCTAssertEqual(solar.toString(), "2021-07-16") 121 | } 122 | func testNext() throws { 123 | let solar: Solar = Solar(fromYmdHms: 2020, month: 1, day: 10, hour: 12, minute: 0, second: 0) 124 | let lunar: Lunar = solar.getLunar() 125 | for i in -50..<50 { 126 | //To-Do Using toFullString() 127 | XCTAssertEqual(lunar.next(days: i).toString(), solar.next(days: i).getLunar().toString()) 128 | } 129 | } 130 | func testLunar27() throws { 131 | let solar: Solar = Solar(fromYmd: 1989, month: 4, day: 28) 132 | let lunar: Lunar = solar.getLunar() 133 | XCTAssertEqual(lunar.day, 23) 134 | } 135 | func testLunar28() throws { 136 | let solar: Solar = Solar(fromYmd: 1990, month: 10, day: 8) 137 | let lunar: Lunar = solar.getLunar() 138 | XCTAssertEqual(lunar.getMonthInGanZhiExact(), "乙酉") 139 | } 140 | func testLunar29() throws { 141 | let solar: Solar = Solar(fromYmd: 1990, month: 10, day: 9) 142 | let lunar: Lunar = solar.getLunar() 143 | XCTAssertEqual(lunar.getMonthInGanZhiExact(), "丙戌") 144 | } 145 | func testLunar30() throws { 146 | let solar: Solar = Solar(fromYmd: 1990, month: 10, day: 8) 147 | let lunar: Lunar = solar.getLunar() 148 | XCTAssertEqual(lunar.getMonthInGanZhi(), "丙戌") 149 | } 150 | func testLunar31() throws { 151 | let solar: Solar = Solar(fromYmdHms: 1987, month: 4, day: 17, hour: 9, minute: 0, second: 0) 152 | let lunar: Lunar = solar.getLunar() 153 | XCTAssertEqual(lunar.toString(), "一九八七年三月二十") 154 | XCTAssertEqual(lunar.getSolar().toYmdHms(), "1987-04-17 09:00:00") 155 | } 156 | func testLunar32() throws { 157 | let lunar: Lunar = Lunar(fromYmdHms: 2034, lunarMonth: 1, lunarDay: 1) 158 | XCTAssertEqual(lunar.getSolar().toYmd(), "2034-02-19") 159 | } 160 | func testLunar33() throws { 161 | let lunar: Lunar = Lunar(fromYmdHms: 2033, lunarMonth: 12, lunarDay: 1) 162 | XCTAssertEqual(lunar.getSolar().toYmd(), "2034-01-20") 163 | } 164 | func testLunar34() throws { 165 | let lunar: Lunar = Lunar(fromYmdHms: 37, lunarMonth: -12, lunarDay: 1) 166 | XCTAssertEqual(lunar.getMonthInChinese(), "闰腊") 167 | } 168 | func testLunar35() throws { 169 | var lunar: Lunar = Lunar(fromYmdHms: 56, lunarMonth: -12, lunarDay: 1) 170 | XCTAssertEqual(lunar.getMonthInChinese(), "闰腊") 171 | 172 | lunar = Lunar(fromYmdHms: 75, lunarMonth: -11, lunarDay: 1) 173 | XCTAssertEqual(lunar.getMonthInChinese(), "闰冬") 174 | 175 | lunar = Lunar(fromYmdHms: 94, lunarMonth: -11, lunarDay: 1) 176 | XCTAssertEqual(lunar.getMonthInChinese(), "闰冬") 177 | 178 | lunar = Lunar(fromYmdHms: 94, lunarMonth: 12, lunarDay: 1) 179 | XCTAssertEqual(lunar.getMonthInChinese(), "腊") 180 | 181 | lunar = Lunar(fromYmdHms: 113, lunarMonth: 12, lunarDay: 1) 182 | XCTAssertEqual(lunar.getMonthInChinese(), "腊") 183 | 184 | lunar = Lunar(fromYmdHms: 113, lunarMonth: -12, lunarDay: 1) 185 | XCTAssertEqual(lunar.getMonthInChinese(), "闰腊") 186 | 187 | lunar = Lunar(fromYmdHms: 5552, lunarMonth: -12, lunarDay: 1) 188 | XCTAssertEqual(lunar.getMonthInChinese(), "闰腊") 189 | } 190 | func testLunar36() throws { 191 | let solar: Solar = Solar(fromYmd: 5553, month: 1, day: 22) 192 | let lunar: Lunar = solar.getLunar() 193 | XCTAssertEqual(lunar.toString(), "五五五二年闰腊月初二") 194 | } 195 | 196 | func testLunar37() throws { 197 | let solar: Solar = Solar(fromYmd: 7013, month: 12, day: 24) 198 | let lunar: Lunar = solar.getLunar() 199 | XCTAssertEqual(lunar.toString(), "七〇一三年闰冬月初四") 200 | } 201 | 202 | func testLunar38() throws { 203 | let lunar: Lunar = Lunar(fromYmdHms: 7013, lunarMonth: -11, lunarDay: 4) 204 | let solar: Solar = lunar.getSolar() 205 | XCTAssertEqual(solar.toString(), "7013-12-24") 206 | } 207 | 208 | func testLunar39() throws { 209 | let solar: Solar = Solar(fromYmd: 1987, month: 4, day: 12) 210 | let lunar: Lunar = solar.getLunar() 211 | XCTAssertEqual(lunar.toString(), "一九八七年三月十五") 212 | } 213 | 214 | func testLunar40() throws { 215 | let solar: Solar = Solar(fromYmd: 1987, month: 4, day: 13) 216 | let lunar: Lunar = solar.getLunar() 217 | XCTAssertEqual(lunar.toString(), "一九八七年三月十六") 218 | } 219 | 220 | func testLunar41() throws { 221 | let solar: Solar = Solar(fromYmd: 4, month: 2, day: 10) 222 | let lunar: Lunar = solar.getLunar() 223 | XCTAssertEqual(lunar.getYearShengXiao(), "鼠") 224 | } 225 | 226 | func testLunar42() throws { 227 | let solar: Solar = Solar(fromYmd: 4, month: 2, day: 9) 228 | let lunar: Lunar = solar.getLunar() 229 | XCTAssertEqual(lunar.getYearShengXiao(), "猪") 230 | } 231 | 232 | func testLunar43() throws { 233 | let solar: Solar = Solar(fromYmd: 1, month: 2, day: 12) 234 | let lunar: Lunar = solar.getLunar() 235 | XCTAssertEqual(lunar.getYearShengXiao(), "鸡") 236 | } 237 | 238 | func testLunar44() throws { 239 | let solar: Solar = Solar(fromYmd: 1, month: 1, day: 1) 240 | let lunar: Lunar = solar.getLunar() 241 | XCTAssertEqual(lunar.getYearShengXiao(), "猴") 242 | } 243 | 244 | func testLunar45() throws { 245 | let solar: Solar = Solar(fromYmd: 2017, month: 2, day: 15) 246 | let lunar: Lunar = solar.getLunar() 247 | XCTAssertEqual(lunar.getDayLu(), "子命互禄 辛命进禄") 248 | } 249 | 250 | func testLunar57() throws { 251 | let solar: Solar = Solar(fromYmd: 1991, month: 2, day: 5) 252 | let lunar: Lunar = solar.getLunar() 253 | XCTAssertEqual(lunar.getMonthInGanZhi(), "庚寅") 254 | } 255 | 256 | func testLunar58() throws { 257 | let solar: Solar = Solar(fromYmd: 2021, month: 3, day: 21) 258 | let lunar: Lunar = solar.getLunar() 259 | XCTAssertEqual(lunar.getOtherFestivals(), ["春社"]) 260 | } 261 | 262 | func testLunar59() throws { 263 | let solar: Solar = Solar(fromYmd: 2022, month: 3, day: 16) 264 | let lunar: Lunar = solar.getLunar() 265 | XCTAssertEqual(lunar.getOtherFestivals(), ["春社"]) 266 | } 267 | 268 | func testLunar60() throws { 269 | let solar: Solar = Solar(fromYmd: 1722, month: 9, day: 25) 270 | let lunar: Lunar = solar.getLunar() 271 | XCTAssertEqual(lunar.getOtherFestivals(), ["秋社"]) 272 | } 273 | 274 | func testLunar61() throws { 275 | let solar: Solar = Solar(fromYmd: 840, month: 9, day: 14) 276 | let lunar: Lunar = solar.getLunar() 277 | XCTAssertEqual(lunar.getOtherFestivals(), ["秋社"]) 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /Tests/SwiftLunarTests/LunarYearTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LunarYearTests.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/20. 6 | // 7 | 8 | import XCTest 9 | @testable import SwiftLunar 10 | 11 | @available(macOS 12.0, *) 12 | final class LunarYearTests: XCTestCase { 13 | func testLunarYearForFirst() throws { 14 | let year: LunarYear = LunarYear(lunarYear: 2021) 15 | XCTAssertEqual(year.toString(), "2021") 16 | } 17 | 18 | func testLunarYearForSecond() throws { 19 | let year: LunarYear = LunarYear(lunarYear: 2017) 20 | XCTAssertEqual(year.getZhiShui(), "二龙治水") 21 | XCTAssertEqual(year.getFenBing(), "二人分饼") 22 | } 23 | 24 | func testLunarYearForThird() throws { 25 | let year: LunarYear = LunarYear(lunarYear: 2018) 26 | XCTAssertEqual(year.getZhiShui(), "二龙治水") 27 | XCTAssertEqual(year.getFenBing(), "八人分饼") 28 | XCTAssertEqual(year.getDeJin(), "三日得金") 29 | } 30 | 31 | func testLunarYearForFourth() throws { 32 | let year: LunarYear = LunarYear(lunarYear: 2021) 33 | XCTAssertEqual(year.getGengTian(), "十一牛耕田") 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /Tests/SwiftLunarTests/MonthTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MonthTests.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/20. 6 | // 7 | import XCTest 8 | @testable import SwiftLunar 9 | 10 | @available(macOS 12.0, *) 11 | final class MonthTests: XCTestCase { 12 | func testMonthForFirst() throws { 13 | let month: SolarMonth = SolarMonth(year: 2019, month: 5) 14 | XCTAssertEqual(month.toString(), "2019-5") 15 | XCTAssertEqual(month.toFullString(), "2019年5月") 16 | } 17 | 18 | func testMonthForSecond() throws { 19 | let month: SolarMonth = SolarMonth(year: 2019, month: 5).next(quantity: 1) 20 | XCTAssertEqual(month.toString(), "2019-6") 21 | XCTAssertEqual(month.toFullString(), "2019年6月") 22 | } 23 | 24 | func testMonthForThird() throws { 25 | let month: SolarMonth = SolarMonth(year: 2022, month: 1).next(quantity: -14) 26 | XCTAssertEqual(month.toString(), "2020-11") 27 | XCTAssertEqual(month.toFullString(), "2020年11月") 28 | } 29 | 30 | func testMonthForfourth() throws { 31 | let month: SolarMonth = SolarMonth(year: 2020, month: 11).next(quantity: 14) 32 | XCTAssertEqual(month.toString(), "2022-1") 33 | XCTAssertEqual(month.toFullString(), "2022年1月") 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Tests/SwiftLunarTests/PhenologyTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PhenologyTests.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/23. 6 | // 7 | import XCTest 8 | @testable import SwiftLunar 9 | 10 | @available(macOS 12.0, *) 11 | final class PhenologyTests: XCTestCase { 12 | func testPhenology1() throws { 13 | let solar: Solar = Solar(fromYmd: 2020, month: 4, day: 23); 14 | let lunar: Lunar = solar.getLunar(); 15 | XCTAssertEqual(lunar.getPhenology(), "萍始生") 16 | } 17 | 18 | func testPhenology2() throws { 19 | let solar: Solar = Solar(fromYmd: 2021, month: 1, day: 15); 20 | let lunar: Lunar = solar.getLunar(); 21 | XCTAssertEqual(lunar.getPhenology(), "雉始雊"); 22 | } 23 | 24 | func testPhenology3() throws { 25 | let solar: Solar = Solar(fromYmd: 2017, month: 1, day: 5); 26 | let lunar: Lunar = solar.getLunar(); 27 | XCTAssertEqual(lunar.getPhenology(), "雁北乡"); 28 | } 29 | 30 | func testPhenology4() throws { 31 | let solar: Solar = Solar(fromYmd: 2020, month: 4, day: 10); 32 | let lunar: Lunar = solar.getLunar(); 33 | XCTAssertEqual(lunar.getPhenology(), "田鼠化为鴽"); 34 | } 35 | 36 | func testPhenology5() throws { 37 | let solar: Solar = Solar(fromYmd: 2020, month: 6, day: 11); 38 | let lunar: Lunar = solar.getLunar(); 39 | XCTAssertEqual(lunar.getPhenology(), "鵙始鸣"); 40 | } 41 | 42 | func testPhenology6() throws { 43 | let solar: Solar = Solar(fromYmd: 2020, month: 6, day: 1); 44 | let lunar: Lunar = solar.getLunar(); 45 | XCTAssertEqual(lunar.getPhenology(), "麦秋至"); 46 | } 47 | 48 | func testPhenology7() throws { 49 | let solar: Solar = Solar(fromYmd: 2020, month: 12, day: 8); 50 | let lunar: Lunar = solar.getLunar(); 51 | XCTAssertEqual(lunar.getPhenology(), "鹖鴠不鸣"); 52 | } 53 | 54 | func testPhenology8() throws { 55 | let solar: Solar = Solar(fromYmd: 2020, month: 12, day: 11); 56 | let lunar: Lunar = solar.getLunar(); 57 | XCTAssertEqual(lunar.getPhenology(), "鹖鴠不鸣"); 58 | } 59 | 60 | func testPhenology9() throws { 61 | let solar: Solar = Solar(fromYmd: 1982, month: 12, day: 22); 62 | let lunar: Lunar = solar.getLunar(); 63 | XCTAssertEqual(lunar.getPhenology(), "蚯蚓结"); 64 | } 65 | 66 | func testPhenology10() throws { 67 | let solar: Solar = Solar(fromYmd: 2021, month: 12, day: 21); 68 | let lunar: Lunar = solar.getLunar(); 69 | XCTAssertEqual(lunar.getSeasonality(), "冬至 初候"); 70 | } 71 | 72 | func testPhenology11() throws { 73 | let solar: Solar = Solar(fromYmd: 2021, month: 12, day: 26); 74 | let lunar: Lunar = solar.getLunar(); 75 | XCTAssertEqual(lunar.getSeasonality(), "冬至 二候"); 76 | } 77 | 78 | func testPhenology12() throws { 79 | let solar: Solar = Solar(fromYmd: 2021, month: 12, day: 31); 80 | let lunar: Lunar = solar.getLunar(); 81 | XCTAssertEqual(lunar.getSeasonality(), "冬至 三候"); 82 | } 83 | 84 | func testPhenology() throws { 85 | let solar: Solar = Solar(fromYmd: 2022, month: 1, day: 5); 86 | let lunar: Lunar = solar.getLunar(); 87 | XCTAssertEqual(lunar.getSeasonality(), "小寒 初候"); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /Tests/SwiftLunarTests/SessonTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SessonTests.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/22. 6 | // 7 | 8 | import XCTest 9 | @testable import SwiftLunar 10 | 11 | @available(macOS 12.0, *) 12 | final class SessonTests: XCTestCase { 13 | func testSession1() throws { 14 | let sesson: SolarSeason = SolarSeason(year: 2019, month: 5) 15 | XCTAssertEqual(sesson.toString(), "2019.2") 16 | XCTAssertEqual(sesson.toFullString(), "2019年2季度") 17 | } 18 | 19 | func testSession2() throws { 20 | let sesson: SolarSeason = SolarSeason(year: 2019, month: 5).next(seasons: 1) 21 | XCTAssertEqual(sesson.toString(), "2019.3") 22 | XCTAssertEqual(sesson.toFullString(), "2019年3季度") 23 | } 24 | 25 | func testSession3() throws { 26 | let sesson: SolarSeason = SolarSeason(year: 2019, month: 5).next(seasons: -2) 27 | XCTAssertEqual(sesson.toString(), "2018.4") 28 | XCTAssertEqual(sesson.toFullString(), "2018年4季度") 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Tests/SwiftLunarTests/ShouXingUtilTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShouXingUtilTests.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/21. 6 | // 7 | import XCTest 8 | @testable import SwiftLunar 9 | 10 | @available(macOS 12.0, *) 11 | final class ShouXingUtilTests: XCTestCase { 12 | func testShouXingUtil() throws { 13 | let w: Double = -4778.5306 + 29.5306 * 0 14 | 15 | XCTAssertEqual(ShouXingUtil.calcShuo(jd: w), -4778) 16 | 17 | // let longitude: Double = w + Solar.J2000 18 | // let sw: Double = floor((longitude + 14 - 2451551) / 29.5306) * (Double.pi * 2) 19 | 20 | // XCTAssertEqual(ShouXingUtil.shuoHigh(w: sw), -4778.468923509471) 21 | 22 | let shuoHighparam: Double = -1017.8760197630929 23 | XCTAssertEqual(ShouXingUtil.msaLonT2(w: shuoHighparam), -0.13083645768655663) 24 | 25 | XCTAssertEqual(ShouXingUtil.mLon(t: -0.13003072702394278, n: 20), -1088.4037694835754) 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /Tests/SwiftLunarTests/SolarTermsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SolarTermsTests.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/20. 6 | // 7 | import XCTest 8 | @testable import SwiftLunar 9 | 10 | @available(macOS 12.0, *) 11 | final class SolarTermsTests: XCTestCase { 12 | func testSolarTerms1() throws { 13 | let solar = Solar(fromYmd: 1986, month: 1, day: 5) 14 | let lunar: Lunar = solar.getLunar() 15 | XCTAssertEqual(lunar.getJie(), "小寒") 16 | XCTAssertEqual(lunar.getJieQi(), "小寒") 17 | XCTAssertEqual(lunar.currentJie?.name, "小寒") 18 | XCTAssertNil(lunar.currentQi) 19 | XCTAssertEqual(lunar.getQi(),"") 20 | XCTAssertEqual(lunar.getPrevJie().name, "大雪") 21 | XCTAssertEqual(lunar.getPrevQi().name, "冬至") 22 | XCTAssertEqual(lunar.getPrevJieQi().name, "冬至") 23 | } 24 | 25 | func testSolarTerms2() throws { 26 | let solar = Solar(fromYmdHms: 1986, month: 1, day: 20, hour: 17, minute: 0, second: 0) 27 | let lunar: Lunar = solar.getLunar() 28 | XCTAssertEqual(lunar.getJie(), "") 29 | XCTAssertEqual(lunar.getJieQi(), "大寒") 30 | XCTAssertNil(lunar.currentJie) 31 | XCTAssertEqual(lunar.currentJieQi!.name, "大寒") 32 | XCTAssertNil(lunar.currentJie) 33 | XCTAssertEqual(lunar.getQi(), "大寒") 34 | XCTAssertEqual(lunar.getNextJie().name, "立春") 35 | XCTAssertEqual(lunar.getNextQi().name, "雨水") 36 | XCTAssertEqual(lunar.getNextJieQi().name, "立春") 37 | } 38 | 39 | func testSolarTerms3() throws { 40 | let solar = Solar(fromYmdHms: 1986, month: 1, day: 20, hour: 14, minute: 0, second: 0) 41 | let lunar: Lunar = solar.getLunar() 42 | XCTAssertEqual(lunar.getPrevJie().name, "小寒") 43 | XCTAssertEqual(lunar.getPrevQi().name, "冬至") 44 | XCTAssertEqual(lunar.getPrevJieQi().name, "小寒") 45 | } 46 | 47 | func testSolarTerms4() throws { 48 | let solar = Solar(fromYmd: 1986, month: 12, day: 7) 49 | let lunar: Lunar = solar.getLunar() 50 | XCTAssertEqual(lunar.getJie(), "大雪") 51 | XCTAssertEqual(lunar.getJieQi(), "大雪") 52 | XCTAssertEqual(lunar.currentJie!.name, "大雪") 53 | XCTAssertEqual(lunar.currentJieQi!.name, "大雪") 54 | XCTAssertNil(lunar.currentQi) 55 | XCTAssertEqual(lunar.getQi(), "") 56 | XCTAssertEqual(lunar.getNextJie().name, "大雪") 57 | XCTAssertEqual(lunar.getNextQi().name, "冬至") 58 | XCTAssertEqual(lunar.getNextJieQi().name, "大雪") 59 | } 60 | func testSolarTerms5() throws { 61 | let solar = Solar(fromYmd: 1986, month: 1, day: 1) 62 | let lunar: Lunar = solar.getLunar() 63 | XCTAssertEqual(lunar.getJie(), "") 64 | XCTAssertEqual(lunar.getJieQi(), "") 65 | XCTAssertNil(lunar.currentJie) 66 | XCTAssertNil(lunar.currentJieQi) 67 | XCTAssertNil(lunar.currentQi) 68 | XCTAssertEqual(lunar.getQi(), "") 69 | XCTAssertEqual(lunar.getPrevJie().name, "大雪") 70 | XCTAssertEqual(lunar.getPrevQi().name, "冬至") 71 | XCTAssertEqual(lunar.getPrevJieQi().name, "冬至") 72 | XCTAssertEqual(lunar.getNextJie().name, "小寒") 73 | XCTAssertEqual(lunar.getNextQi().name, "大寒") 74 | XCTAssertEqual(lunar.getNextJieQi().name, "小寒") 75 | } 76 | 77 | func testSolarTerms6() throws { 78 | let solar = Solar(fromYmd: 1986, month: 1, day: 1) 79 | let lunar: Lunar = solar.getLunar() 80 | XCTAssertEqual(lunar.getJie(), "") 81 | XCTAssertEqual(lunar.getJieQi(), "") 82 | XCTAssertNil(lunar.currentJie) 83 | XCTAssertNil(lunar.currentJieQi) 84 | XCTAssertNil(lunar.currentQi) 85 | XCTAssertEqual(lunar.getQi(), "") 86 | XCTAssertEqual(lunar.getPrevJie().name, "大雪") 87 | XCTAssertEqual(lunar.getPrevQi().name, "冬至") 88 | XCTAssertEqual(lunar.getPrevJieQi().name, "冬至") 89 | XCTAssertEqual(lunar.getNextJie().name, "小寒") 90 | XCTAssertEqual(lunar.getNextQi().name, "大寒") 91 | XCTAssertEqual(lunar.getNextJieQi().name, "小寒") 92 | } 93 | 94 | func testSolarTerms7() throws { 95 | let solarTermsTable: [String: String] = [ 96 | "冬至": "2021-12-21 23:59:09", 97 | "小寒": "2022-01-05 17:13:54", 98 | "大寒": "2022-01-20 10:38:56", 99 | "立春": "2022-02-04 04:50:36", 100 | "雨水": "2022-02-19 00:42:50", 101 | "惊蛰": "2022-03-05 22:43:34", 102 | "春分": "2022-03-20 23:33:15", 103 | "清明": "2022-04-05 03:20:03", 104 | "谷雨": "2022-04-20 10:24:07", 105 | "立夏": "2022-05-05 20:25:46", 106 | "小满": "2022-05-21 09:22:25", 107 | "芒种": "2022-06-06 00:25:37", 108 | "夏至": "2022-06-21 17:13:40", 109 | "小暑": "2022-07-07 10:37:49", 110 | "大暑": "2022-07-23 04:06:49", 111 | "立秋": "2022-08-07 20:28:57", 112 | "处暑": "2022-08-23 11:15:59", 113 | "白露": "2022-09-07 23:32:07", 114 | "秋分": "2022-09-23 09:03:31", 115 | "寒露": "2022-10-08 15:22:16", 116 | "霜降": "2022-10-23 18:35:31", 117 | "立冬": "2022-11-07 18:45:18", 118 | "小雪": "2022-11-22 16:20:18", 119 | "大雪": "2022-12-07 11:46:04" 120 | ] 121 | let solar: Solar = Solar(fromYmd: 2022, month: 7, day: 15) 122 | let result: [String: Solar] = solar.getLunar().getJieQiTable() 123 | for entry in solarTermsTable { 124 | let name: String = entry.key 125 | XCTAssertEqual(result[name]!.toYmdHms(), entry.value) 126 | } 127 | } 128 | 129 | func testSolarTerms8() throws { 130 | let solarTermsTable: [String: String] = [ 131 | "冬至": "1985-12-22 06:07:40", 132 | "小寒": "1986-01-05 23:28:02", 133 | "大寒": "1986-01-20 16:46:12", 134 | "立春": "1986-02-04 11:07:42", 135 | "雨水": "1986-02-19 06:57:31", 136 | "惊蛰": "1986-03-06 05:12:08", 137 | "春分": "1986-03-21 06:02:41", 138 | "清明": "1986-04-05 10:06:07", 139 | "谷雨": "1986-04-20 17:12:08", 140 | "立夏": "1986-05-06 03:30:36", 141 | "小满": "1986-05-21 16:27:55", 142 | "芒种": "1986-06-06 07:44:23", 143 | "夏至": "1986-06-22 00:29:57", 144 | "小暑": "1986-07-07 18:00:45", 145 | "大暑": "1986-07-23 11:24:23", 146 | "立秋": "1986-08-08 03:45:36", 147 | "处暑": "1986-08-23 18:25:47", 148 | "白露": "1986-09-08 06:34:37", 149 | "秋分": "1986-09-23 15:58:52", 150 | "寒露": "1986-10-08 22:06:45", 151 | "霜降": "1986-10-24 01:14:11", 152 | "立冬": "1986-11-08 01:12:49", 153 | "小雪": "1986-11-22 22:44:20", 154 | "大雪": "1986-12-07 18:00:56" 155 | ] 156 | let solar: Solar = Solar(fromYmd: 1986, month: 7, day: 15) 157 | let result: [String: Solar] = solar.getLunar().getJieQiTable() 158 | for entry in solarTermsTable { 159 | let name: String = entry.key 160 | XCTAssertEqual(result[name]!.toYmdHms(), entry.value) 161 | } 162 | } 163 | 164 | func testSolarTerms9() throws { 165 | let lunar: Lunar = Lunar(fromYmdHms: 2012, lunarMonth: 9, lunarDay: 1) 166 | XCTAssertEqual(lunar.getJieQiTable()["白露"]!.toYmdHms(), "2012-09-07 13:29:00") 167 | } 168 | 169 | func testSolarTerms10() throws { 170 | let lunar: Lunar = Lunar(fromYmdHms: 2050, lunarMonth: 12, lunarDay: 1) 171 | XCTAssertEqual(lunar.getJieQiTable()["大雪"]!.toYmdHms(), "2050-12-07 06:41:00") 172 | } 173 | 174 | func testSolarTerms11() throws { 175 | let solar: Solar = Solar(fromYmd: 2021, month: 12, day: 21) 176 | let lunar: Lunar = solar.getLunar() 177 | XCTAssertEqual(lunar.getJieQi(), "冬至") 178 | XCTAssertEqual(lunar.getJie(), "") 179 | XCTAssertEqual(lunar.getQi(), "冬至") 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /Tests/SwiftLunarTests/SolarTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SolarTests.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/12. 6 | // 7 | 8 | import XCTest 9 | @testable import SwiftLunar 10 | 11 | @available(macOS 12.0, *) 12 | final class SolarTests: XCTestCase { 13 | func testSolar() throws { 14 | // This is an example of a functional test case. 15 | // Use XCTAssert and related functions to verify your tests produce the correct 16 | // results. 17 | let solar: Solar = Solar(fromYmd: 2019, month: 5, day: 1) 18 | XCTAssertEqual(solar.toString(), "2019-05-01") 19 | XCTAssertEqual(solar.toFullString(), "2019-05-01 00:00:00 星期三 (劳动节) 金牛座") 20 | // XCTAssertEqual(solar.getLunar().toString(), "二〇一九年三月廿七") 21 | // XCTAssertEqual(solar.getLunar().toFullString(), "二〇一九年三月廿七 己亥(猪)年 戊辰(龙)月 戊戌(狗)日 子(鼠)时 纳音[平地木 大林木 平地木 桑柘木] 星期三 西方白虎 星宿[参水猿](吉) 彭祖百忌[戊不受田田主不祥 戌不吃犬作怪上床] 喜神方位[巽](东南) 阳贵神方位[艮](东北) 阴贵神方位[坤](西南) 福神方位[艮](东北) 财神方位[坎](正北) 冲[(壬辰)龙] 煞[北]") 22 | } 23 | 24 | func testFromYmd() throws { 25 | var solar: Solar = Solar(fromYmd: 2020, month: 1, day: 23) 26 | XCTAssertEqual(solar.next(days: 1).toString(), "2020-01-24") 27 | /// 仅工作日,跨越春节假期 28 | XCTAssertEqual(solar.next(days: 1, onlyWorkday: true).toString(), "2020-02-03") 29 | 30 | solar = Solar(fromYmd: 2020, month: 2, day: 3) 31 | XCTAssertEqual(solar.next(days: -3).toString(), "2020-01-31") 32 | /// 仅工作日,跨越春节假期 33 | XCTAssertEqual(solar.next(days: -3, onlyWorkday: true).toString(), "2020-01-21") 34 | 35 | solar = Solar(fromYmd: 2020, month: 2, day: 9) 36 | XCTAssertEqual(solar.next(days: 6).toString(), "2020-02-15") 37 | /// 仅工作日,跨越周末 38 | XCTAssertEqual(solar.next(days: 6, onlyWorkday: true).toString(), "2020-02-17") 39 | 40 | solar = Solar(fromYmd: 2020, month: 1, day: 17) 41 | XCTAssertEqual(solar.next(days: 1).toString(), "2020-01-18") 42 | /// 仅工作日,周日调休按上班算 43 | XCTAssertEqual(solar.next(days: 1, onlyWorkday: true).toString(), "2020-01-19") 44 | } 45 | 46 | func testIsLeepYear() throws { 47 | XCTAssertEqual(SolarUtil.isLeapYear(year: 1500), false) 48 | } 49 | 50 | func testSolarGetterAndSetter() { 51 | let dateFormat: DateFormatter = DateFormatter() 52 | dateFormat.dateFormat = "yyyy-MM-dd HH:mm:ss" 53 | let date: Date = dateFormat.date(from: "2022-07-22 18:59:56")! 54 | let solar: Solar = Solar(fromDate: date) 55 | // let lunar: Lunar = solar.getLunar() 56 | XCTAssertEqual(solar.calendar, date) 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /Tests/SwiftLunarTests/SolarWeekTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SolarWeekTests.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/20. 6 | // 7 | 8 | import XCTest 9 | @testable import SwiftLunar 10 | 11 | @available(macOS 12.0, *) 12 | final class SolarWeekTests: XCTestCase { 13 | func testSolarWeekForFirst() throws { 14 | let week: SolarWeek = SolarWeek(year: 2021, month: 5, day: 1, start: 0) 15 | XCTAssertEqual(week.index, 1) 16 | } 17 | 18 | func testSolarWeekForSecond() throws { 19 | let week: SolarWeek = SolarWeek(year: 2021, month: 5, day: 4, start: 2) 20 | XCTAssertEqual(week.index, 2) 21 | } 22 | 23 | func testSolarWeekForThird() throws { 24 | let week: SolarWeek = SolarWeek(year: 2022, month: 5, day: 1, start: 0) 25 | XCTAssertEqual(week.index, 1) 26 | } 27 | 28 | func testSolarWeekForFourth() throws { 29 | let week: SolarWeek = SolarWeek(year: 2022, month: 5, day: 1, start: 1) 30 | XCTAssertEqual(week.index, 1) 31 | } 32 | 33 | func testSolarWeekForFifth() throws { 34 | let week: SolarWeek = SolarWeek(year: 2022, month: 3, day: 6, start: 0) 35 | XCTAssertEqual(week.getIndexInYear(), 11) 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /Tests/SwiftLunarTests/TaoistTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TaoistTests.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/23. 6 | // 7 | import XCTest 8 | @testable import SwiftLunar 9 | 10 | @available(macOS 12.0, *) 11 | final class TaoistTests: XCTestCase { 12 | func testTaoist1() throws { 13 | let taoist: Taoist = Taoist.fromLunar(lunar: Lunar(fromYmdHms: 2021, lunarMonth: 10, lunarDay: 17, hour: 18, minute: 0, second: 0)) 14 | XCTAssertEqual(taoist.toString(), "四七一八年十月十七") 15 | XCTAssertEqual(taoist.toFullString(), "道歷四七一八年,天運辛丑年,己亥月,癸酉日。十月十七日,酉時。") 16 | } 17 | 18 | func testTaoist2() throws { 19 | let taoist1: Taoist = Taoist.fromYmd(year: 4718, month: 10, day: 18); 20 | var l1: [String] = [] 21 | for taoistFestival in taoist1.getFestivals() { 22 | l1.append(taoistFestival.name) 23 | } 24 | XCTAssertEqual(l1, ["地母娘娘圣诞", "四时会"]) 25 | 26 | 27 | let taoist2 = Lunar(fromYmdHms: 2021, lunarMonth: 10, lunarDay: 18).getTaoist() 28 | var l2: [String] = [] 29 | for taoistFestival in taoist2.getFestivals() { 30 | l2.append(taoistFestival.name) 31 | } 32 | XCTAssertEqual(l2, ["地母娘娘圣诞", "四时会"]) 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /Tests/SwiftLunarTests/TimeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TimeTests.swift 3 | // 4 | // 5 | // Created by 睿宁 on 2022/7/23. 6 | // 7 | import XCTest 8 | @testable import SwiftLunar 9 | 10 | @available(macOS 12.0, *) 11 | final class TimeTests: XCTestCase { 12 | func testTime1() throws { 13 | let timeTable: [String: String] = [ 14 | "23:00": "子", 15 | "00:59": "子", 16 | "23:30": "子", 17 | "01:00": "丑", 18 | "02:59": "丑", 19 | "01:30": "丑", 20 | "03:00": "寅", 21 | "04:59": "寅", 22 | "03:30": "寅", 23 | "05:00": "卯", 24 | "06:59": "卯", 25 | "05:30": "卯", 26 | "07:00": "辰", 27 | "08:59": "辰", 28 | "07:30": "辰", 29 | "09:00": "巳", 30 | "10:59": "巳", 31 | "09:30": "巳", 32 | "11:00": "午", 33 | "12:59": "午", 34 | "11:30": "午", 35 | "13:00": "未", 36 | "14:59": "未", 37 | "13:30": "未", 38 | "15:00": "申", 39 | "16:59": "申", 40 | "15:30": "申", 41 | "17:00": "酉", 42 | "18:59": "酉", 43 | "17:30": "酉", 44 | "19:00": "戌", 45 | "20:59": "戌", 46 | "19:30": "戌", 47 | "21:00": "亥", 48 | "22:59": "亥", 49 | "21:30": "亥", 50 | "": "子", 51 | "23:01:01": "子", 52 | "其他": "子", 53 | "21:01:01": "亥" 54 | ] 55 | for entry in timeTable { 56 | let hm: String = entry.key 57 | let zhi: String = entry.value 58 | XCTAssertEqual(LunarUtil.convertTime(hm: hm), zhi) 59 | } 60 | } 61 | 62 | func testTime2() throws { 63 | let timeTable: [String: String] = [ 64 | "2020-4,5,23:00": "戊", 65 | //早子时 66 | "2020-4,5,00:59": "丙", 67 | //晚子时 68 | "2020-4,5,23:30": "戊", 69 | 70 | "2020-4,5,01:00": "丁", 71 | "2020-4,5,02:59": "丁", 72 | "2020-4,5,01:30": "丁", 73 | 74 | "2020-4,5,03:00": "戊", 75 | "2020-4,5,04:59": "戊", 76 | "2020-4,5,03:30": "戊", 77 | 78 | "2020-4,5,05:00": "己", 79 | "2020-4,5,06:59": "己", 80 | "2020-4,5,05:30": "己", 81 | 82 | "2020-4,5,07:00": "庚", 83 | "2020-4,5,08:59": "庚", 84 | "2020-4,5,07:30": "庚", 85 | 86 | "2020-4,5,09:00": "辛", 87 | "2020-4,5,10:59": "辛", 88 | "2020-4,5,09:30": "辛", 89 | 90 | "2020-4,5,11:00": "壬", 91 | "2020-4,5,12:59": "壬", 92 | "2020-4,5,11:30": "壬", 93 | 94 | "2020-4,5,13:00": "癸", 95 | "2020-4,5,14:59": "癸", 96 | "2020-4,5,13:30": "癸", 97 | 98 | "2020-4,5,15:00": "甲", 99 | "2020-4,5,16:59": "甲", 100 | "2020-4,5,15:30": "甲", 101 | 102 | "2020-4,5,17:00": "乙", 103 | "2020-4,5,18:59": "乙", 104 | "2020-4,5,17:30": "乙", 105 | 106 | "2020-4,5,19:00": "丙", 107 | "2020-4,5,20:59": "丙", 108 | "2020-4,5,19:30": "丙", 109 | 110 | "2020-4,5,21:00": "丁", 111 | "2020-4,5,22:59": "丁", 112 | "2020-4,5,21:30": "丁", 113 | 114 | "2020-4,5,null": "丙", 115 | 116 | "2020-4,5,": "丙", 117 | "2020-4,5,23:01:01": "戊", 118 | "2020-4,5,其他": "丙", 119 | "2020-4,5,80:90": "丙", 120 | 121 | "2020-4,5,21:01:01": "丁", 122 | 123 | "2020-4,2,23:00": "壬", 124 | "2020-4,2,11:20": "丙" 125 | ] 126 | for entry in timeTable { 127 | var hour: Int = 0, minute: Int = 0 128 | let time: String = entry.key 129 | let year: Int = Int(time.prefix(4))! 130 | let month: Int = Int(time[time.index(time.startIndex, offsetBy: 4)..= 5) { 134 | hour = Int(hm.prefix(2))! 135 | minute = Int(hm[hm.index(hm.startIndex, offsetBy: 3)..= 5) { 219 | hour = Int(hm.prefix(2))! 220 | minute = Int(hm[hm.index(hm.startIndex, offsetBy: 3)..