Add Magento custom validation to a form field using adding  a new rule using `$.validator.addMethod`

using `$.validator.addMethod` we can **create number of custom rules and via class name we can access those custom rules**.

so back to the question,  need of question is without using calendar validate input fields like days/month/year.

so assuming where you adding these days/month/year fields that wrap with form tag, In this form magento default validation added `data-mage-init='{"validation":{}}`' or via js.

create all days/month/year fields under form or add below html code

    <div class="field date field-dob"  data-mage-init='{
            "Vendor_Module/js/custom-validation-dob":{
                "day" : "[name=\"day\"]",
                "month" : "[name=\"month\"]",
                "year" : "[name=\"year\"]",
                "classPrefix": "custom-dob",
                "maxYearDiff": 150
            }
        }'>
        <label class="label" for="dob">
            <span><?= __('Your Birthday'); ?></span>
        </label>
        <div class="input-box customer-dob">
             <div class="dob-day">
                 <label for="day"><?= __('DD'); ?></label>
                <input type="text" id="day" name="day"  title="<?= __('Day'); ?>" class="input-text required-entry" autocomplete="off">
            </div>
            
            <div class="dob-month">
                 <label for="month"><?= __('MM'); ?></label>
                <input type="text" id="month" name="month" title="<?= __('Month'); ?>" class="input-text required-entry" autocomplete="off">
            </div>
           
            <div class="dob-year">
                <label for="year"><?= __('YYYY'); ?></label>
                <input type="text" id="year" name="year" title="<?= __('Year'); ?>" class="input-text required-entry" autocomplete="off">
            </div>    
        </div>
    </div>


**Alter or update the HTML as your need expect name attribute of input field. if need to modify name attribute too then do same change in**    

    data-mage-init='{
        "Vendor_Module/js/custom-validation-dob":{
            "day" : "[name=\"day\"]",
            "month" : "[name=\"month\"]",
            "year" : "[name=\"year\"]",
            "classPrefix": "custom-dob",
            "maxYearDiff": 150
        }
    }'

 **as well with respective fields.**


Now create a js file `custom-validation-dob.js` under your module something like that   `Vendor/Module/view/frontend/web/js/custom-validation-dob.js` the paste below js code 

    define([
        'jquery',   
        'jquery/ui',
        'jquery/validate',
        'mage/translate'
    ], function($){
        'use strict';
    
        var enterValueIsNumeric = function (input) {
           return (input - 0) == input && input.length > 0;
        }
            
        return function(config, element) {
            var dayObj = $(element).find(config.day || '[name="day"]');
            var monthObj = $(element).find(config.month || '[name="month"]');
            var yearObj = $(element).find(config.year || '[name="year"]');        
            var classPrefix = config.classPrefix || 'custom';
            var maxYearDiff = config.maxYearDiff ||  100; // max limit for year gap
    
            $.validator.addMethod(
                classPrefix+"-day-validate",
                function(value, element) {
                    var result = false,
                        validatorObj = this,
                        isElementOptional = this.optional(element),
                        days = 31; // just to assume no value set on year and month fields
                    
                    var year = yearObj.val();
                    var month = monthObj.val();
                    
                    var currentDateObj = new Date();
                    var maxMonth = currentDateObj.getMonth() + 1;
                    var maxYear = currentDateObj.getFullYear();
                    var currentDay = currentDateObj.getDate();
                    
                    var message = $.mage.__("Please enter valid day value in this field.");
                    
                   
                    if(enterValueIsNumeric(value)) {
                        if(year && month){ //Checks days in the specific month with year
                            days = new Date(year, month, 0).getDate();
                        }
                        
                        result = days >= value;
                        if(result && year == maxYear && month == maxMonth) { // for current year & month
                            result = currentDay >= value;
                            message = $.mage.__("Entered day value will be less then or equal to %1 that is current day because Entered Year and Month value respectively equal to current year and month value.").replace('%1', currentDay);
                        }
                    } 
                         
                    if (!result) {
                        validatorObj.customDayMessage = message;
                    }                
                    return isElementOptional || result;
                }, function () {
                    return this.customDayMessage;
                }            
            );
    
            $.validator.addMethod(
                classPrefix+"-month-validate",
                function(value, element) {
                    var result = false,
                        validatorObj = this,
                        isElementOptional = this.optional(element);
                    var year = yearObj.val();
                    
                    var currentDateObj = new Date();
                    var maxMonth = currentDateObj.getMonth() + 1;
                    var maxYear = currentDateObj.getFullYear();
                   
                    var message = $.mage.__("Please enter valid month value in this field.");
                    if(enterValueIsNumeric(value)) {
                        result = ( value >= 1 && value <= 12);
                        if(result && year == maxYear) { // For current year 
                            result = ( value <= maxMonth);
                            message = $.mage.__("Entered month value will be less then or equal to %1 that is current month because Entered Year value is equal to current year value.").replace('%1', maxMonth);
                        } 
                    } 
                               
                    if (!result) {
                        validatorObj.customMonthMessage = message;
                    }
                    return isElementOptional || result; 
                }, function () {
                    return this.customMonthMessage;
                }
            );
    
            $.validator.addMethod(
                classPrefix+"-year-validate",
                function(value, element) {
                    var result = false,
                        validatorObj = this,
                        isElementOptional = this.optional(element),
                        prevDateObj = new Date(),
                        currentDateObj = new Date();
                        
                    prevDateObj.setFullYear(prevDateObj.getFullYear() - maxYearDiff);
                    currentDateObj.setFullYear(currentDateObj.getFullYear());
                    
                    var minYear = prevDateObj.getFullYear();
                    var maxYear = currentDateObj.getFullYear(); // because DOB value will be less then the current year
                    var message = $.mage.__("Please enter valid year value in this field and year value will be in between %1 and %2").replace('%1', minYear).replace('%2', maxYear);
                                   
                    if(enterValueIsNumeric(value)) {
                        result = (value.length == 4 && value >= minYear && value <= maxYear ); // always be year value in 4 digit
                    }
                                    
                    if (!result) {
                        validatorObj.customYearMessage = message;
                    }
                    return isElementOptional || result;
                }, function () {
                    return this.customYearMessage;
                }
                
            );     
            
            // binding class with respective element to apply validation rule properly.
            dayObj.addClass(classPrefix+"-day-validate");
            monthObj.addClass(classPrefix+"-month-validate");
            yearObj.addClass(classPrefix+"-year-validate");
        }
    });


using these 2 code set, first html markup and second magento custom js will help to **validate calendar like function**. and these rules are linked also so proper validation come in picture hope this will match all you expectation mention in question. 


## Add on - 
For future reuse of this custom js with valid name instead of full path, **alias the js path with a good name**. 

So create a requirejs config file `requirejs-config.js` in your module `Vendor/Module/view/frontend/requirejs-config.js` if not exist and add below code

    var config = {
        "map": {
            "*": {
                "customValidationForDMY": "Vendor_Module/js/custom-validation-dob" // D = Day,M = Month, Y = Year
            }
        }
    };

then in above mention html code update

    data-mage-init='{
        "Vendor_Module/js/custom-validation-dob":{
            "day" : "[name=\"day\"]",
            "month" : "[name=\"month\"]",
            "year" : "[name=\"year\"]",
            "classPrefix": "custom-dob",
            "maxYearDiff": 150
        }
    }'

with 

    data-mage-init='{
        "customValidationForDMY":{
            "day" : "[name=\"day\"]",
            "month" : "[name=\"month\"]",
            "year" : "[name=\"year\"]",
            "classPrefix": "custom-dob",
            "maxYearDiff": 150
        }
    }'

In given sample I used **Vendor_Module**, In your case this will be change with your respective module name.

Any help will be appreciated.